[ignition-cmake] 01/03: Imported Upstream version 0.2.0~pre1

Jose Luis Rivero jrivero-guest at moszumanska.debian.org
Mon Nov 20 16:45:56 UTC 2017


This is an automated email from the git hooks/post-receive script.

jrivero-guest pushed a commit to branch master
in repository ignition-cmake.

commit 81939d8416fc703165ca9fcfef67994c6643a065
Author: Jose Luis Rivero <jrivero at osrfoundation.org>
Date:   Mon Nov 20 16:21:17 2017 +0000

    Imported Upstream version 0.2.0~pre1
---
 .hg_archival.txt                                   |   6 +
 CMakeLists.txt                                     | 108 +++
 MIGRATION.md                                       | 405 +++++++++
 README.md                                          |  31 +
 bitbucket-pipelines.yml                            |  19 +
 cmake/Export.hh.in                                 |  64 ++
 cmake/FindAVCODEC.cmake                            |  19 +
 cmake/FindAVDEVICE.cmake                           |  23 +
 cmake/FindAVFORMAT.cmake                           |  19 +
 cmake/FindAVUTIL.cmake                             |  19 +
 cmake/FindDL.cmake                                 |  55 ++
 cmake/FindFreeImage.cmake                          |  78 ++
 cmake/FindGTS.cmake                                |  19 +
 cmake/FindSWSCALE.cmake                            |  19 +
 cmake/FindTINYXML2.cmake                           |  52 ++
 cmake/FindUUID.cmake                               |  19 +
 cmake/IgnCMake.cmake                               |  37 +
 cmake/IgnCheckSSE.cmake                            | 283 +++++++
 cmake/IgnCodeCoverage.cmake                        | 114 +++
 cmake/IgnConfigureBuild.cmake                      | 225 +++++
 cmake/IgnConfigureProject.cmake                    | 188 +++++
 cmake/IgnCreateDocs.cmake                          |  50 ++
 cmake/IgnImportTarget.cmake                        | 121 +++
 cmake/IgnPackaging.cmake                           | 268 ++++++
 cmake/IgnPkgConfig.cmake                           | 113 +++
 cmake/IgnRonn2Man.cmake                            |  64 ++
 cmake/IgnSetCompilerFlags.cmake                    | 341 ++++++++
 cmake/IgnUtils.cmake                               | 906 +++++++++++++++++++++
 cmake/cmake_uninstall.cmake.in                     |  21 +
 cmake/cpack_options.cmake.in                       |  28 +
 cmake/ign_auto_headers.hh.in                       |  23 +
 cmake/ignition-config.cmake.in                     |  71 ++
 cmake/pkgconfig/ignition.pc.in                     |  12 +
 cmake/upload_doc.sh.in                             |  29 +
 config/ignition-cmake-config.cmake.in              |  35 +
 configure.bat                                      |  15 +
 doc/CMakeLists.txt                                 |   1 +
 examples/CMakeLists.txt                            |  74 ++
 examples/ign_configure_build/CMakeLists.txt        |   4 +
 examples/ign_configure_build/README.md             |   0
 examples/ign_configure_build/doc/CMakeLists.txt    |   0
 .../ign_configure_build/include/CMakeLists.txt     |   0
 examples/ign_configure_build/src/CMakeLists.txt    |   0
 examples/ign_configure_build/test/CMakeLists.txt   |   0
 examples/junit_fail.xml.in                         |   8 +
 examples/junit_pass.xml.in                         |   6 +
 examples/prerelease/CMakeLists.txt                 |   4 +
 examples/prerelease/README.md                      |   0
 examples/prerelease/doc/CMakeLists.txt             |   0
 examples/prerelease/include/CMakeLists.txt         |   0
 examples/prerelease/src/CMakeLists.txt             |   0
 examples/prerelease/test/CMakeLists.txt            |   0
 test/CMakeLists.txt                                |   9 +
 test/cmake_minimum_required.bash                   |  75 ++
 tools/code_check.sh                                |  28 +
 55 files changed, 4108 insertions(+)

diff --git a/.hg_archival.txt b/.hg_archival.txt
new file mode 100644
index 0000000..9993077
--- /dev/null
+++ b/.hg_archival.txt
@@ -0,0 +1,6 @@
+repo: d8ed439c5f00b7073f27f16aebb168da9b398751
+node: 8a614c5dca581b2051775eb3215045b6e1b40f00
+branch: default
+latesttag: ignition-cmake_0.1.1
+latesttagdistance: 13
+changessincelatesttag: 13
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..32b5150
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,108 @@
+cmake_minimum_required(VERSION 3.5.1 FATAL_ERROR)
+
+#============================================================================
+# Initialize the project
+#============================================================================
+
+#--------------------------------------
+# Initialize the IGNITION_CMAKE_DIR variable with the location of the cmake
+# directory that sits next to this find-module.
+set(IGNITION_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake")
+
+#--------------------------------------
+# Add the location of this package's cmake directory to the CMAKE_MODULE_PATH
+list(APPEND CMAKE_MODULE_PATH "${IGNITION_CMAKE_DIR}")
+
+#--------------------------------------
+# include the master IgnCMake module
+include(IgnCMake)
+
+#--------------------------------------
+# Set up the project
+ign_configure_project(cmake 0.2.0 VERSION_SUFFIX pre1)
+
+#============================================================================
+# Configure the package to be installed
+#============================================================================
+
+#--------------------------------------
+# Create configuration and installation variables
+set(ign_config_input  "${CMAKE_CURRENT_SOURCE_DIR}/config/ignition-cmake-config.cmake.in")
+set(ign_config_output "${PROJECT_NAME_LOWER}-config.cmake")
+set(ign_version_output "${PROJECT_NAME_LOWER}-config-version.cmake")
+set(ign_config_install_dir "${IGN_LIB_INSTALL_DIR}/cmake/${PROJECT_NAME_LOWER}")
+
+#--------------------------------------
+# Configure and install the config file
+configure_package_config_file(
+  ${ign_config_input}
+  ${ign_config_output}
+  INSTALL_DESTINATION ${ign_config_install_dir}
+  NO_CHECK_REQUIRED_COMPONENTS_MACRO)
+
+#--------------------------------------
+# Configure and install the version file
+write_basic_package_version_file(
+  ${CMAKE_CURRENT_BINARY_DIR}/${ign_version_output}
+  VERSION "${PROJECT_VERSION_FULL}"
+  COMPATIBILITY SameMajorVersion)
+
+install(
+  FILES
+    ${CMAKE_CURRENT_BINARY_DIR}/${ign_config_output}
+    ${CMAKE_CURRENT_BINARY_DIR}/${ign_version_output}
+  DESTINATION ${ign_config_install_dir}
+  COMPONENT cmake)
+
+
+#============================================================================
+# Install the files for this package
+#============================================================================
+set(ign_modules_install_dir "${ign_config_install_dir}/cmake${PROJECT_VERSION_MAJOR}")
+
+file(GLOB modules "cmake/*.cmake")
+file(GLOB templates "cmake/*.in")
+
+install(
+  FILES ${modules} ${templates}
+  DESTINATION ${ign_modules_install_dir}
+  COMPONENT modules)
+
+file(GLOB pkgconfig_templates "cmake/pkgconfig/*.in")
+
+install(
+  FILES ${pkgconfig_templates}
+  DESTINATION ${ign_modules_install_dir}/pkgconfig
+  COMPONENT modules)
+
+message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}")
+
+include(CTest)
+if (BUILD_TESTING)
+  add_subdirectory(test)
+
+  #============================================================================
+  # Build examples
+  #============================================================================
+  # find_package expects cmakeN (e.g. cmake0, cmake1, ... depending on the major version of ign-cmake)
+  # to be in the build folder because that is where the ignition-cmake-config.cmake file is located
+  # before it is installed
+  if (UNIX)
+    # make a symlink on unix
+    execute_process(
+      COMMAND
+        ${CMAKE_COMMAND} -E create_symlink ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_BINARY_DIR}/cmake${PROJECT_VERSION_MAJOR})
+  else()
+    # otherwise copy the files one by one
+    # use configure_file(... COPYONLY) since it will run again if files change
+    foreach (filename ${modules} ${templates})
+      get_filename_component(file ${filename} NAME)
+      configure_file(${filename} ${CMAKE_BINARY_DIR}/cmake${PROJECT_VERSION_MAJOR}/${file} COPYONLY)
+    endforeach()
+    foreach (filename ${pkgconfig_templates})
+      get_filename_component(file ${filename} NAME)
+      configure_file(${filename} ${CMAKE_BINARY_DIR}/cmake${PROJECT_VERSION_MAJOR}/pkgconfig/${file} COPYONLY)
+    endforeach()
+  endif()
+  add_subdirectory(examples)
+endif()
diff --git a/MIGRATION.md b/MIGRATION.md
new file mode 100644
index 0000000..6583c03
--- /dev/null
+++ b/MIGRATION.md
@@ -0,0 +1,405 @@
+# Migration Instructions
+
+This file provides instructions for `ignition` library developers to adopt the
+`ignition-cmake` package into their own library's build system. This document
+is primarily targeted at ignition libraries that existed before `ignition-cmake`
+was available, but it might also be useful for getting a new `ignition` project
+started.
+
+The first section goes over changes that your library **must** make in order to
+be compatible with `ignition-cmake`. The second section mentions some utilities
+provided by `ignition-cmake` which might make your project's CMake scripts more
+clean and maintainable, but use of those utilities is not required. The third
+section details some of the new CMake features that we'll be using through
+`ignition-cmake` and explains why we want to use those features. The last
+section describes some CMake anti-patterns which we should aggressively avoid
+as we move forward.
+
+# 1. Required Changes
+
+You can find examples of projects that have been set up to use `ign-cmake` in
+the repos of `ign-common` (branch: `CMakeRefactor`) and `ign-math`
+(branch: `CMakeRefactor-3`). The following is a checklist to help you make sure
+your project is migrated properly.
+
+### Clear out your top-level `CMakeLists.txt` entirely
+That's right, just throw it all out.
+
+### Begin your top-level `CMakeLists.txt` with `cmake_minimum_required(VERSION 3.5.1 FATAL_ERROR)`
+
+We're migrating to 3.5 because it provides many valuable features that we are
+now taking advantage of.
+
+### Then call `find_package(ignition-cmake0 REQUIRED)`
+
+This will find `ignition-cmake` and load up all its useful features for you.
+
+### Then call `ign_configure_project(<project> <version>)`
+
+This is a wrapper for cmake's native `project(~)` command which additionally
+sets a bunch of variables that will be needed by the `ignition-cmake` macros and
+functions.
+
+### Then search for each dependency using `ign_find_package(~)`
+
+We now have a cmake macro `ign_find_package(~)` which is a wrapper for the
+native cmake `find_package(~)` function, which additionally:
+
+1. Collects build errors and build warnings so that they can all be printed out
+at the end of the script, instead of quitting immediately upon encountering an
+error.
+
+2. Automatically populates the dependencies for your project's pkgconfig file
+and cmake config file.
+
+A variety of arguments are available to guide the behavior of
+`ign_find_package(~)`. Most of them will not be needed in most situations, but
+you should consider reading them over once just in case they might be relevant
+for you. The macro's documentation is available in
+`ign-cmake/cmake/IgnUtils.cmake` just above definition of `ign_find_package(~)`.
+Feel free to ask questions about any of its arguments that are unclear.
+
+Any operations that might need to be performed while searching for a package
+should be done in a find-module. See the section on anti-patterns for more
+information on writing find-modules.
+
+### Then call `ign_configure_build(~)`
+
+This macro accepts the argument `QUIT_IF_BUILD_ERRORS` which you should pass to
+it to get the standard behavior for the ignition projects. If for some reason
+you want to handle build errors in your own way, you can leave that argument
+out and then do as you please after the macro finishes.
+
+### Finally, call `ign_create_packages()`
+
+After this, your top-level `CMakeLists.txt` is finished. The remaining changes
+listed below must be applied throughout your directory tree.
+
+### Change instances of `PROJECT_<type>_VERSION` variables to `PROJECT_VERSION_<type>`.
+
+In the original ignition CMake scripts, we define variables for the components
+of the library version: `PROJECT_MAJOR_VERSION`, `PROJECT_MINOR_VERSION`, and
+`PROJECT_PATCH_VERSION`. While there is nothing inherently wrong with these
+variable names, in CMake 3+ the `project(~)` command automatically defines the
+following variables: `PROJECT_VERSION_MAJOR`, `PROJECT_VERSION_MINOR`, and
+`PROJECT_VERSION_PATCH`. The pattern that is automatically provided by
+`project(~)` is consistent with how CMake names project variables in general,
+and adopting their convention will reduce the friction that we experience when
+interfacing with a wide variety of native CMake utilities. It's also beneficial
+to embrace the "single source of truth" pattern.
+
+### Change instances of `IGN_PROJECT_NAME` to `IGN_DESIGNATION`
+
+We've had a variable called `IGN_PROJECT_NAME` which refers to the `<suffix>`
+in the `ignition-<suffix>` name of each project. I felt that the name of the
+variable was too similar to the `PROJECT_NAME` variable that is automatically
+defined by CMake, as well as the `PROJECT_NAME[_NO_VERSION][_UPPER/_LOWER]` that
+we define for convenience. Instead of referring to both as `[IGN_]PROJECT_NAME`,
+I thought it would be better to use clear and distinct words to distinguish
+them. Therefore the `<suffix>` part of the project name is now referred to as
+`IGN_DESIGNATION`, and we provide `IGN_DESIGNATION[_LOWER/_UPPER]` for
+convenience.
+
+### Do not use `append_to_cached_string` or `append_to_cached_list` anymore.
+
+These macros have been removed because they were facilitating bad practices
+which we should aggressively avoid as we move forward. To put it briefly, we
+should not be using the CMake cache except to allow human users to set build
+options. For more explanation about why and how we should avoid using the cache,
+see the below section on CMake anti-patterns.
+
+### Specify `TYPE` and `SOURCES` arguments in `ign_build_tests(~)`
+
+Previously, ignition libraries would set a `TEST_TYPE` variable before calling
+`ign_build_tests(~)`, and that variable would be used by the macro to determine
+the type of tests it should create. This resulted in some anti-patterns where
+the `TEST_TYPE` variable would be set somewhere far away from the call to
+`ign_build_tests(~)`, making it unclear to a human reader what type of tests the
+call would produce. Instead, we now explicitly specify the test type using the
+`TYPE` tag when calling the macro, and to avoid confusion with backwards
+compatibility, the `SOURCES` tag must be used before specifying sources. We are
+also introducing some new arguments:
+
+`LIB_DEPS`: Libraries or (preferably) targets which follow the `LIB_DEPS` tag
+will be linked (using `target_link_libraries`) to *each* test that gets
+generated by the macro. Note that `gtest`, `gtest_main`, and your project's
+library target will automatically be linked to each test by the macro (for Unix
+systems, `pthread` is also added, since gtest requires it on those platforms).
+Since the tests link to your library's target, all of your library's "interface"
+dependencies will also be automatically linked to each test. In most cases, this
+will make `LIB_DEPS` unnecessary, but it is still provided for edge cases.
+Note that when individual tests depend on additional libraries, those individual
+tests should be linked to their dependencies using
+`target_link_libraries(<test_name> <dependency>)` after the call to
+`ign_build_tests(~)`. `LIB_DEPS` should only be used for dependencies that are
+needed by (nearly) all of the tests.
+
+`INCLUDE_DIRS`: Include directories that need to be visible to all (or most) of
+the tests can be specified using the `INCLUDE_DIRS` tag. Note that the macro
+will automatically include the "interface include directories" of your project's
+library target, as well as the `PROJECT_SOURCE_DIR` and `PROJECT_BINARY_DIR`.
+Also note that all of the "interface include directories" of any targets that
+you pass to `LIB_DEPS` will automatically be visible to all the tests, so this
+tag should be even less commonly needed than `LIB_DEPS`.
+
+### Move your project's `cmake/config.hh.in` file to `include/ignition/<project>/config.hh.in`
+
+The `config.hh.in` file has traditionally lived in the `cmake` subdirectory of
+each project, but that subdirectory should be deleted at the end of the
+migration process. Since `config.hh.in` may need to be different between
+projects, each project should still maintain its own copy, and that copy should
+be standardized to the source include directory.
+
+### Use imported targets instead of package variables
+
+Calling `find_package(~)` will generally produce a set of variables which look
+like `DEPENDENCY_FOUND`, `DEPENDENCY_LIBRARIES`, `DEPENDENCY_INCLUDE_DIRS`, and
+`DEPENDENCY_CXX_FLAGS`. These variables are often passed to cmake functions like
+`target_add_library(my_target ${DEPENDENCY_LIBRARIES})`. These variables often
+contain explicit full system paths. This results in package information which
+is not relocatable, and that may cause significant problems when distributing
+pre-built packages, or when relocating a package within a system.
+
+Instead, we should prefer passing **only targets** into `target_link_libraries(~)`.
+When using `target_link_libraries(~)` to link targets instead of libraries, all
+of the "interface" properties of the dependency target will be linked to the
+dependent target, like a transitive property. An "interface" property is a
+property which a target specifies as being required by any packages that want to
+interface with it. This includes the interface include directories, interface
+compiler flags, interface libraries, among other properties. These properties
+will be propagated in a way which is relocatable. Also, be sure to specify
+`PUBLIC` or `PRIVATE` depending on whether libraries which depend on your
+project will need to link to symbols in the library that your project is linking
+to.
+
+Note that you must also specify which targets' interface include directories
+will be needed by libraries which depend on your project's library. This should
+be done using `ign_target_interface_include_directories(<project_target> <dependency_targets>)`.
+That function will add the interface include directories of the dependency
+targets that you pass in to the interface include directory list of
+`<project_target>` in a way which is relocatable by using generator expressions.
+This is in contrast to just using
+`target_include_directories(<project_target> ${DEPENDENCY_INCLUDE_DIRS})` which
+will not be relocatable, because `${DEPENDENCY_INCLUDE_DIRS}` just contains an
+explicit list of full paths to the directories.
+
+**BEWARE**: Very often, a target name might be identical to the name of the
+library that it is meant to represent. This can cause confusion for cmake when
+calling `target_link_libraries(~)`, because subtle typos might cause it to
+select a library even though you meant to specify a target. To avoid this,
+target names can contain a scoping operator `::` which is not allowed in the
+names of libraries. When an item containing `::` is passed to
+`target_link_libraries(~)`, CMake will know that a target is being specified,
+and it will throw an error and quit if that target is not found, instead of
+failing quietly or subtly. Therefore, we should always exercise the practice of
+using `::` in the names of any imported targets that we intend to use.
+`ignition-cmake` will automatically export all ignition library targets to have
+the name `ignition-<project><major_version>::ignition-<project><major_version>`
+(for example, `ignition-common0::ignition-common0`). When creating a cmake
+find-module, the macro `ign_import_target(~)` should be used generate an
+imported target which follows this convention. More about creating find-modules
+can be found in the section on anti-patterns.
+
+### Remove all arguments from `ign_install_library()`
+
+To reduce complexity, this macro no longer takes in any arguments, and instead
+uses the standardized target name and export name.
+
+### Replace calls to `#include "ignition/<project>/System.hh"` with `#include "ignition/<project>/Export.hh"`, and delete the file `System.hh`.
+
+Up until now, we've been maintaining a "System" header in each ignition library.
+This is being replaced by a set of auto-generated headers, because some of the
+individual projects' implementations had errors or issues in them. The new
+auto-generated headers will enforce consistency and compatibility across all of
+the ignition projects. The header is also being renamed because the role of the
+header is to provide macros that facilitate exporting the library, therefore it
+seems more appropriate to name it "Export" instead of "System". Nothing in the
+header is interacting with the operating system, so the current name feels like
+somewhat of a misnomer (presumably the name "System" came from the fact that the
+macros are system-dependent, but I think naming the header after the role that
+it's performing would be more appropriate).
+
+### Replace `IGNITION_<VISIBLE/HIDDEN>` with `IGNITION_<PROJECT>_<VISIBLE/HIDDEN>` in all headers
+
+The export (a.k.a. visibility) macros used by each ignition library must be
+unique. Different ignition libraries might depend on each other, and the
+compiler/linker would be misinformed about which symbols to export if two
+different libraries share the same export macro.
+
+### Move all find-modules in your project's `cmake/` directory to your `ign-cmake` repo, and submit a pull request for them
+
+We are centralizing all find-modules into `ign-cmake` so that everyone benefits
+from them, and we get a single place to maintain them.
+
+### Remove the entire `cmake/` subdirectory from your project
+
+Once the above steps are complete, your project's `cmake/` subdirectory should
+no longer be needed. If your `cmake/` subdirectory contained some features
+that are not already present in `ign-cmake`, then you should add those
+features to `ign-cmake` and submit a pull request. I will try to be very prompt
+about reviewing and approving those PRs.
+
+
+
+
+# 2. Recommended Changes
+
+The following changes are not necessary, but may improve the readability and
+maintainability of your CMake code. Use of these utilities is optional.
+
+### GLOB up library source files and unit test source files using `ign_get_libsources_and_unittests(sources tests)`
+
+Placing this in `src/CMakeLists.txt` will collect all the source files in the
+directory and sort them into a `source` variable (containing the library sources)
+and a `tests` variable (containing the unit test sources).
+
+If there are files that you want to exclude from either of these lists, you can
+use `list(REMOVE_ITEM <list> <filenames>)` after calling the function. That
+approach can be used to conditionally remove files from a list (see
+`ign-common/src/CMakeLists.txt` for an example). Alternatively, if you always
+want a file to be excluded, you can change its extension (e.g. `*.cc.backup` or
+`.cc.old`) until a later time when you want it to be used again.
+
+### Use `ign_install_all_headers(~)` in `include/ignition/<project>/CMakeLists.txt`
+
+Using this macro will install all files ending in `*.h` and `*.hh` in the
+current source directory as well as the subdirectory named `detail` (if it
+exists). It will also configure your project's `<project>.hh` and `config.hh.in`
+files and install them.
+
+You can use the argument `ADDITIONAL_DIRS` to specify additional subdirectories
+to install, and the argument `EXCLUDE` can specify files that should not be
+installed.
+
+### Use `ign_get_sources(~)` in `test/<type>/CMakeLists.txt` to collect source files
+
+Similar to `ign_get_libsources_and_unittests(~)` except it only produces one
+list of source files, which is sufficient to be passed to `ign_build_tests(~)`.
+
+
+
+
+# 3. Anti-patterns to avoid
+
+### Do not use `include(${cmake_dir}/ModuleName.cmake)`
+
+Files that end in `*.cmake` are known as "modules" and are not meant to be
+invoked using the fully qualified filename. Instead, the path that leads up to
+the module should be added to `${CMAKE_MODULE_PATH}` if it is not in there
+already (the module path of `ignition-cmake` will automatically be added when
+you call `find_package(ignition-cmake# REQUIRED)`, so you do not have to worry
+about this for `ign-cmake` modules). After that, the module should be invoked
+using `include(ModuleName)` with no path or extension. CMake will automatically
+find the appropriate file.
+
+### Do not use `include(FindSomePackage)`
+
+When a `*.cmake` file begins with the word `Find`, it is a special type of
+cmake module known as a find-module. Its purpose is to search for a package
+after being invoked by the command `find_package(SomePackage)`. Notice that the
+`SomePackage` argument must match the string of characters in between `Find` and
+`.cmake` in the filename `FindSomePackage.cmake`. Case matters. This is not just
+a convention; it is a cmake requirement.
+
+Note that while using `ignition-cmake`, you should be using `ign_find_package(~)`
+instead of the native `find_package(~)` command. It does the same thing, except
+that it adds some additional functionality which is important for ensuring
+correctness in the package configuration files that we generate for our projects.
+
+### Do not name a module `Find<Module>.cmake` unless it is genuinely a find-module
+
+We had files named `FindOS.cmake` which checked the operating system type, and
+`FindSSE.cmake` which checked the SSE compatibility of the build machine.
+Neither of these were searching for packages, so neither of them should begin
+with the word `Find`. As explained above, that pattern of filename is reserved
+for find-modules that are supposed to search for packages after being invoked by
+the `find_package(~)` command.
+
+### All package search behavior must go in its own find-module
+
+Up until now, we have generally used the `SearchForStuff.cmake` file to find
+packages that our libraries depend on. Any logic or procedures that are needed
+to find a package will often end up buried in that file, making it difficult to
+transfer the procedure between different projects (often leading to redundant
+copies of the same procedure, ultimately resulting in different projects using
+divergent methods of varying quality for solving the same problem). Instead, any
+procedures or operations that are needed to find a package dependency should be
+put into a file called `Find<PACKAGE>.cmake` where `<PACKAGE>` should be
+replaced with the name of the package (often this is done in all uppercase
+letters). This `Find<PACKAGE>.cmake` should be added to `ign-cmake/cmake`.
+Pull requests for adding find-modules will be reviewed and approved as quickly
+as possible. This way, all projects can benefit from any one person's effort in
+writing a good quality find-module.
+
+In many cases, a package that we depend on will be distributed with a pkgconfig
+(`*.pc`) file. In such a case, `ignition-cmake` provides a macro that can easily
+find the package and create an imported target for it. Simply use `include(IgnPkgConfig)`
+and then `ign_pkg_check_modules(~)` in your find-module, and you are done. An
+example of a simple case of this can be found in `ign-cmake/cmake/FindGTS.cmake`.
+
+If certain version-based behavior is needed, that must be handled within the
+find-module. A simple example using pkgconfig can be found in
+`ign-cmake/cmake/FindAVDEVICE.cmake`.
+
+Sometimes a package may be needed but there is no guarantee that a pkgconfig
+file will be available for it. For an example of how to handle that, see
+`ign-cmake/cmake/FindFreeImage.cmake`.
+
+Some libraries are never distributed with a pkgconfig file. For an example of
+how to create a find-module when a pkgconfig file is guaranteed to not exist,
+see `ign-cmake/cmake/FindDL.cmake`. Note that you must manually specify the
+variables `<PACKAGE>_PKGCONFIG_ENTRY` and `<PACKAGE>_PKGCONFIG_TYPE` in such
+cases. The entry will have to be the name of library (or libraries), preceded by
+`-l`, while the type must be `PROJECT_PKGCONFIG_LIBS`.
+
+### Do not use `CACHE INTERNAL`
+
+There is almost never a situation where `CACHE INTERNAL` is appropriate for us
+to use. If you think you need to use it, you probably don't. If you're certain
+you need to use it, you should discuss it with someone first. Using
+`CACHE INTERNAL` can have very negative side effects that may easily go
+unnoticed because the internally cached data isn't readily visible to a
+developer.
+
+To understand why `CACHE INTERNAL` should be unnecessary, it is important to
+understand variable scope in cmake. When you call `add_subdirectory(~)`, you
+will enter a child scope. Each child scope can see all the variables that were
+set in its ancestors (parent directory, grandparent directory, etc.). This
+allows variables to easily trickle down the directory tree. A child directory
+can override a variable that was set in its parent directory, and that change
+will trickle down into all the children of that child, but the parent and the
+parent's other children will not see the change. This is an intentional feature
+to make sure that the special needs of one child do not impact its siblings (or
+cousins, etc).
+
+If for some reason a child *should* change a variable for its parent and
+siblings, then the `set(~)` function accepts the `PARENT_SCOPE` option. If a
+child needs to change a variable in a way that is supposed to impact its parent,
+grandparent, siblings, cousins, etc, then there is almost certainly something
+wrong with the way the cmake script is designed. An operation (or variable) that
+needs to be visible to such a broad scope should simply be performed (or set) in
+a higher scope rather than added to the cache.
+
+Note that a cmake function will behave as though it has a child scope, while a
+macro will behave as though it has the same scope as the parent that calls it.
+If the role of the function/macro is to effectively copy/paste a bunch of
+text into the file that calls it, it should be written as a macro. If the role
+is to perform some complex operations and then return just a small number of
+variables, then it should be written as a function, and `set( ... PARENT_SCOPE)`
+should be used to provide the variable to the parent scope.
+
+This is not to say that the cache itself should never be used. The cache is
+useful for exposing build options to the user. However, in those cases, a type
+(such as `FILEPATH`, `PATH`, `STRING`, or `BOOL`) must be specified instead of
+`INTERNAL`. When providing a bool option, you should prefer to use the command
+`option(<variable> "Description" <default>)`. When providing a string option
+where a set of valid choices is known ahead of time, use
+`set(<variable> "Default Variable Value" CACHE STRING "Description")` followed
+by `set_property(CACHE <variable> PROPERTY STRINGS <list_of_choices>)`. This
+will explicitly inform the user of their choices for the option.
+
+### Do not use `link_directories(~)`
+
+The convention when finding packages in cmake is to provide full library paths,
+so specifying a link directory should not generally be needed, except in edge
+cases where a find-module does not comply with the established convention.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..71704ff
--- /dev/null
+++ b/README.md
@@ -0,0 +1,31 @@
+# Ignition CMake
+
+** CMake modules to be used by the Ignition projects. **
+
+This package is required to build ignition projects, as well as to link your own
+projects against them. It provides modules that are used to find dependencies
+of ignition projects and generate cmake targets for consumers of ignition projects
+to link against.
+
+## Installation
+
+Standard installation can be performed in UNIX systems using the following
+steps:
+
+ - mkdir build/
+ - cd build/
+ - cmake ..
+ - sudo make install
+
+### Contribution guidelines ###
+
+* Writing tests
+* Code review
+* Other guidelines
+
+## Uninstallation
+
+To uninstall the software installed with the previous steps:
+
+ - cd build/
+ - sudo make uninstall
diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml
new file mode 100644
index 0000000..7189dcb
--- /dev/null
+++ b/bitbucket-pipelines.yml
@@ -0,0 +1,19 @@
+# This is a sample build configuration for C++.
+# Check our guides at https://confluence.atlassian.com/x/VYk8Lw for more examples.
+# Only use spaces to indent your .yml configuration.
+# -----
+# You can specify a custom docker image from Docker Hub as your build environment.
+image: ubuntu:xenial
+
+pipelines:
+  default:
+    - step:
+        script: # Modify the commands below to build your repository.
+          - apt-get update
+          - apt-get -y install cmake build-essential lcov
+          - mkdir build
+          - cd build
+          - cmake ..
+          - make
+          - make test
+          - make install
diff --git a/cmake/Export.hh.in b/cmake/Export.hh.in
new file mode 100644
index 0000000..138751c
--- /dev/null
+++ b/cmake/Export.hh.in
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 Open Source Robotics Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+/*
+ * ==========================================================================
+ * This file was automatically generated by CMake; do not modify it directly.
+ * To modify this file, make changes to ign-cmake/cmake/Export.hh.in
+ * ==========================================================================
+*/
+
+#ifndef IGNITION_ at IGN_DESIGNATION_UPPER@_EXPORT_HH_
+#define IGNITION_ at IGN_DESIGNATION_UPPER@_EXPORT_HH_
+
+// The detail/Export.hh header is automatically generated by CMake, which only
+// provides the system-dependent implementations of these macros, with no
+// commentary or explanation, so we configure this public-facing header which
+// leverages the auto-generated macros but provides commentary for them.
+#include "ignition/@IGN_DESIGNATION_LOWER@/detail/Export.hh"
+
+
+#ifndef IGNITION_ at IGN_DESIGNATION_UPPER@_VISIBLE
+/// For ignition- at IGN_DESIGNATION_LOWER@ developers: Apply this macro to
+/// ignition- at IGN_DESIGNATION_LOWER@ functions and classes which consumers of
+/// this library will need to be able to call from their own programs or
+/// libraries.
+#define IGNITION_ at IGN_DESIGNATION_UPPER@_VISIBLE \
+  DETAIL_IGNITION_ at IGN_DESIGNATION_UPPER@_VISIBLE
+#endif
+
+
+#ifndef IGNITION_ at IGN_DESIGNATION_UPPER@_HIDDEN
+/// For ignition- at IGN_DESIGNATION_LOWER@ developers: Apply this macro to
+/// ignition- at IGN_DESIGNATION_LOWER@ functions and classes which must not be
+/// used by consumers of this library. By default, this property is applied to
+/// all classes and functions which are not tagged with IGNITION_ at IGN_DESIGNATION_UPPER@_VISIBLE,
+/// so this does not generally need to be used.
+#define IGNITION_ at IGN_DESIGNATION_UPPER@_HIDDEN \
+  DETAIL_IGNITION_ at IGN_DESIGNATION_UPPER@_HIDDEN
+#endif
+
+
+#ifndef IGN_DEPRECATED
+/// For ignition- at IGN_DESIGNATION_LOWER@ developers: Use this macro to indicate
+/// that a function or class has been deprecated and should no longer be used.
+/// A version should be specified to provide context to the user about when the
+/// function became deprecated.
+#define IGN_DEPRECATED(version) IGN_DEPRECATED_ALL_VERSIONS
+#endif
+
+#endif
diff --git a/cmake/FindAVCODEC.cmake b/cmake/FindAVCODEC.cmake
new file mode 100644
index 0000000..b7c820d
--- /dev/null
+++ b/cmake/FindAVCODEC.cmake
@@ -0,0 +1,19 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# Find avcodec
+include(IgnPkgConfig)
+ign_pkg_check_modules(AVCODEC libavcodec)
diff --git a/cmake/FindAVDEVICE.cmake b/cmake/FindAVDEVICE.cmake
new file mode 100644
index 0000000..f4d751c
--- /dev/null
+++ b/cmake/FindAVDEVICE.cmake
@@ -0,0 +1,23 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# Find AV device.
+set(av_major ${AVDEVICE_FIND_VERSION_MAJOR})
+set(av_minor ${AVDEVICE_FIND_VERSION_MINOR})
+set(av_patch ${AVDEVICE_FIND_VERSION_PATCH})
+
+include(IgnPkgConfig)
+ign_pkg_check_modules(AVDEVICE libavdevice>=${av_major}.${av_minor}.${av_patch})
diff --git a/cmake/FindAVFORMAT.cmake b/cmake/FindAVFORMAT.cmake
new file mode 100644
index 0000000..cdde0c5
--- /dev/null
+++ b/cmake/FindAVFORMAT.cmake
@@ -0,0 +1,19 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# Find AV format
+include(IgnPkgConfig)
+ign_pkg_check_modules(AVFORMAT libavformat)
diff --git a/cmake/FindAVUTIL.cmake b/cmake/FindAVUTIL.cmake
new file mode 100644
index 0000000..205ffa6
--- /dev/null
+++ b/cmake/FindAVUTIL.cmake
@@ -0,0 +1,19 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# Find avutil
+include(IgnPkgConfig)
+ign_pkg_check_modules(AVUTIL libavutil)
diff --git a/cmake/FindDL.cmake b/cmake/FindDL.cmake
new file mode 100644
index 0000000..ce5df37
--- /dev/null
+++ b/cmake/FindDL.cmake
@@ -0,0 +1,55 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# Find libdl
+
+# NOTE: libdl is a system library, so it does not come with pkgconfig metadata
+
+# If we cannot find the header or the library, we will switch this to false
+set(DL_FOUND true)
+
+# Search for the header
+find_path(DL_INCLUDE_DIRS dlfcn.h)
+if(DL_INCLUDE_DIRS)
+  message(STATUS "Looking for dlfcn.h - found")
+else(DL_INCLUDE_DIRS)
+  message(STATUS "Looking for dlfcn.h - not found")
+  set(DL_FOUND false)
+endif()
+
+# Search for the library
+find_library(DL_LIBRARIES dl)
+if(DL_LIBRARIES)
+  message(STATUS "Looking for libdl - found")
+else(DL_LIBRARIES)
+  message(STATUS "Looking for libdl - not found")
+  set(DL_FOUND false)
+endif()
+
+if(DL_FOUND)
+  include(IgnImportTarget)
+  ign_import_target(DL)
+endif()
+
+# We need to manually specify the pkgconfig entry (and type of entry) for dl,
+# because ign_pkg_check_modules does not work for it.
+set(DL_PKGCONFIG_ENTRY "-ldl")
+set(DL_PKGCONFIG_TYPE PROJECT_PKGCONFIG_LIBS)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(
+  DL
+  REQUIRED_VARS DL_FOUND)
diff --git a/cmake/FindFreeImage.cmake b/cmake/FindFreeImage.cmake
new file mode 100644
index 0000000..f78449a
--- /dev/null
+++ b/cmake/FindFreeImage.cmake
@@ -0,0 +1,78 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# Find FreeImage
+
+# Grab the version numbers requested by the call to find_package(~)
+set(major_version ${FreeImage_FIND_VERSION_MAJOR})
+set(minor_version ${FreeImage_FIND_VERSION_MINOR})
+
+# Set the full version number
+set(full_version ${major_version}.${minor_version})
+
+include(IgnPkgConfig)
+ign_pkg_check_modules_quiet(FreeImage FreeImage>=${full_version})
+
+# If we don't have PkgConfig, or if PkgConfig failed, then do a manual search
+if(NOT FreeImage_FOUND)
+  message(STATUS "FreeImage.pc not found, we will search for "
+                 "FreeImage_INCLUDE_DIRS and FreeImage_LIBRARIES")
+
+  find_path(FreeImage_INCLUDE_DIRS FreeImage.h)
+  if(NOT FreeImage_INCLUDE_DIRS)
+    message(STATUS "Looking for FreeImage.h - not found")
+    message(STATUS "Missing: Unable to find FreeImage.h")
+  else(NOT FreeImage_INCLUDE_DIRS)
+    # Check the FreeImage header for the right version
+    set(testFreeImageSource ${CMAKE_CURRENT_BINARY_DIR}/CMakeTmp/test_freeimage.cc)
+    set(FreeImage_test_output "")
+    set(FreeImage_compile_output "")
+    file(WRITE ${testFreeImageSource}
+      "#include <FreeImage.h>\nint main () { if (FREEIMAGE_MAJOR_VERSION >= ${major_version} && FREEIMAGE_MINOR_VERSION >= ${minor_version}) return 1; else return 0;} \n")
+
+    try_run(FREEIMAGE_RUNS
+            FREEIMAGE_COMPILES
+            ${CMAKE_CURRENT_BINARY_DIR}
+            ${testFreeImageSource}
+            CMAKE_FLAGS -DINCLUDE_DIRECTORIES=${FreeImage_INCLUDE_DIRS}
+            RUN_OUTPUT_VARIABLE FreeImage_test_output
+            COMPILE_OUTPUT_VARIABLE FreeImage_compile_output)
+
+    if(NOT FREEIMAGE_COMPILES)
+      message(STATUS "FreeImage test failed to compile - This may indicate a build system bug")
+      return()
+    endif(NOT FREEIMAGE_COMPILES)
+
+    if(NOT FREEIMAGE_RUNS)
+      message(STATUS "Invalid FreeImage Version. Requires ${major_version}.${minor_version}")
+    endif(NOT FREEIMAGE_RUNS)
+  endif(NOT FreeImage_INCLUDE_DIRS)
+
+  find_library(FreeImage_LIBRARIES freeimage)
+  if(FreeImage_LIBRARIES)
+    set(FreeImage_FOUND true)
+  else()
+    set("Looking for libfreeimage - not found")
+    message(STATUS "Missing: Unable to find libfreeimage")
+  endif(FreeImage_LIBRARIES)
+
+  if(FreeImage_FOUND)
+    # Create the imported target for FreeImage if we found it
+    include(IgnImportTarget)
+    ign_import_target(FreeImage)
+  endif()
+
+endif()
diff --git a/cmake/FindGTS.cmake b/cmake/FindGTS.cmake
new file mode 100644
index 0000000..8ea65cc
--- /dev/null
+++ b/cmake/FindGTS.cmake
@@ -0,0 +1,19 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# Find GNU Triangulation Surface Library
+include(IgnPkgConfig)
+ign_pkg_check_modules(GTS gts)
diff --git a/cmake/FindSWSCALE.cmake b/cmake/FindSWSCALE.cmake
new file mode 100644
index 0000000..88a55b6
--- /dev/null
+++ b/cmake/FindSWSCALE.cmake
@@ -0,0 +1,19 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# Find libswscale format
+include(IgnPkgConfig)
+ign_pkg_check_modules(SWSCALE libswscale)
diff --git a/cmake/FindTINYXML2.cmake b/cmake/FindTINYXML2.cmake
new file mode 100644
index 0000000..e131045
--- /dev/null
+++ b/cmake/FindTINYXML2.cmake
@@ -0,0 +1,52 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# Find tinyxml2. Only debian distributions package tinyxml with a pkg-config.
+
+include(IgnPkgConfig)
+
+# Use pkg_check_modules to start
+ign_pkg_check_modules_quiet(TINYXML2 tinyxml2)
+
+# If that failed, then fall back to manual detection (necessary for MacOS)
+if(NOT TINYXML2_FOUND)
+
+  message(STATUS "Attempting manual search for tinyxml2")
+
+  find_path(TINYXML2_INCLUDE_DIRS tinyxml2.h ${TINYXML2_INCLUDE_DIRS} ENV CPATH)
+  find_library(TINYXML2_LIBRARIES NAMES tinyxml2)
+  set(TINYXML2_FOUND true)
+
+  if(NOT TINYXML2_INCLUDE_DIRS)
+    message(STATUS "Looking for tinyxml2 headers - not found")
+    set(TINYXML2_FOUND false)
+  endif()
+
+  if(NOT TINYXML2_LIBRARIES)
+    message (STATUS "Looking for tinyxml2 library - not found")
+    set(TINYXML2_FOUND false)
+  endif()
+
+  if(TINYXML2_FOUND)
+    ign_create_imported_target(TINYXML2)
+  endif()
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(
+    TINYXML2
+    REQUIRED_VARS TINYXML2_FOUND)
+
+endif()
diff --git a/cmake/FindUUID.cmake b/cmake/FindUUID.cmake
new file mode 100644
index 0000000..151cfd1
--- /dev/null
+++ b/cmake/FindUUID.cmake
@@ -0,0 +1,19 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# Find uuid
+include(IgnPkgConfig)
+ign_pkg_check_modules(UUID uuid)
diff --git a/cmake/IgnCMake.cmake b/cmake/IgnCMake.cmake
new file mode 100644
index 0000000..a26d549
--- /dev/null
+++ b/cmake/IgnCMake.cmake
@@ -0,0 +1,37 @@
+#.rst
+# IgnCMake
+# --------
+#
+# Includes a set of modules that are needed for building the ignition libraries
+#
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#============================================================================
+# ignition-cmake modules
+#============================================================================
+include(IgnUtils)
+include(IgnConfigureProject)
+include(IgnPackaging)
+include(IgnCreateDocs)
+include(IgnSetCompilerFlags)
+include(IgnConfigureBuild)
+
+
+#============================================================================
+# Native cmake modules
+#============================================================================
+include(CMakePackageConfigHelpers)
+include(CMakeParseArguments)
diff --git a/cmake/IgnCheckSSE.cmake b/cmake/IgnCheckSSE.cmake
new file mode 100644
index 0000000..dc5b498
--- /dev/null
+++ b/cmake/IgnCheckSSE.cmake
@@ -0,0 +1,283 @@
+# Copyright (c) 2012 Petroules Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#     Redistributions of source code must retain the above copyright notice, this
+#     list of conditions and the following disclaimer.  Redistributions in binary
+#     form must reproduce the above copyright notice, this list of conditions and
+#     the following disclaimer in the documentation and/or other materials
+#     provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Modified for ignition libraries - 2017
+
+# Based on the Qt 5 processor detection code, so should be very accurate
+# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h
+# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64)
+
+# Regarding POWER/PowerPC, just as is noted in the Qt source,
+# "There are many more known variants/revisions that we do not handle/detect."
+
+set(archdetect_c_code "
+#if defined(__arm__) || defined(__TARGET_ARCH_ARM)
+    #if defined(__ARM_ARCH_7__) \\
+        || defined(__ARM_ARCH_7A__) \\
+        || defined(__ARM_ARCH_7R__) \\
+        || defined(__ARM_ARCH_7M__) \\
+        || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
+        #error cmake_ARCH armv7
+    #elif defined(__ARM_ARCH_6__) \\
+        || defined(__ARM_ARCH_6J__) \\
+        || defined(__ARM_ARCH_6T2__) \\
+        || defined(__ARM_ARCH_6Z__) \\
+        || defined(__ARM_ARCH_6K__) \\
+        || defined(__ARM_ARCH_6ZK__) \\
+        || defined(__ARM_ARCH_6M__) \\
+        || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
+        #error cmake_ARCH armv6
+    #elif defined(__ARM_ARCH_5TEJ__) \\
+        || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
+        #error cmake_ARCH armv5
+    #else
+        #error cmake_ARCH arm
+    #endif
+#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
+    #error cmake_ARCH i386
+#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
+    #error cmake_ARCH x86_64
+#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
+    #error cmake_ARCH ia64
+#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
+      || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC)  \\
+      || defined(_M_MPPC) || defined(_M_PPC)
+    #if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
+        #error cmake_ARCH ppc64
+    #else
+        #error cmake_ARCH ppc
+    #endif
+#endif
+
+#error cmake_ARCH unknown
+")
+
+# Set ppc_support to TRUE before including this file or ppc and ppc64
+# will be treated as invalid architectures since they are no longer supported by Apple
+
+if(APPLE AND CMAKE_OSX_ARCHITECTURES)
+    # On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set
+    # First let's normalize the order of the values
+
+    # Note that it's not possible to compile PowerPC applications if you are using
+    # the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
+    # disable it by default
+    # See this page for more information:
+    # http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
+
+    # Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
+    # On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
+
+    foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
+        if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
+            set(osx_arch_ppc TRUE)
+        elseif("${osx_arch}" STREQUAL "i386")
+            set(osx_arch_i386 TRUE)
+        elseif("${osx_arch}" STREQUAL "x86_64")
+            set(osx_arch_x86_64 TRUE)
+        elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
+            set(osx_arch_ppc64 TRUE)
+        else()
+            message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
+        endif()
+    endforeach()
+
+    # Now add all the architectures in our normalized order
+    if(osx_arch_ppc)
+        list(APPEND ARCH ppc)
+    endif()
+
+    if(osx_arch_i386)
+        list(APPEND ARCH i386)
+    endif()
+
+    if(osx_arch_x86_64)
+        list(APPEND ARCH x86_64)
+    endif()
+
+    if(osx_arch_ppc64)
+        list(APPEND ARCH ppc64)
+    endif()
+else()
+    file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
+
+    enable_language(C)
+
+    # Detect the architecture in a rather creative way...
+    # This compiles a small C program which is a series of ifdefs that selects a
+    # particular #error preprocessor directive whose message string contains the
+    # target architecture. The program will always fail to compile (both because
+    # file is not a valid C program, and obviously because of the presence of the
+    # #error preprocessor directives... but by exploiting the preprocessor in this
+    # way, we can detect the correct target architecture even when cross-compiling,
+    # since the program itself never needs to be run (only the compiler/preprocessor)
+    try_run(
+        run_result_unused
+        compile_result_unused
+        "${CMAKE_BINARY_DIR}"
+        "${CMAKE_BINARY_DIR}/arch.c"
+        COMPILE_OUTPUT_VARIABLE ARCH
+        CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
+    )
+
+    # Parse the architecture name from the compiler output
+    string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
+
+    # Get rid of the value marker leaving just the architecture name
+    string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}")
+
+    # If we are compiling with an unknown architecture this variable should
+    # already be set to "unknown" but in the case that it's empty (i.e. due
+    # to a typo in the code), then set it to unknown
+    if (NOT ARCH)
+        set(ARCH unknown)
+    endif()
+endif()
+
+
+# Check if SSE instructions are available on the machine where
+# the project is compiled.
+
+IF (ARCH MATCHES "i386" OR ARCH MATCHES "x86_64")
+  IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
+     EXEC_PROGRAM(cat ARGS "/proc/cpuinfo" OUTPUT_VARIABLE CPUINFO)
+
+     STRING(REGEX REPLACE "^.*(sse2).*$" "\\1" SSE_THERE ${CPUINFO})
+     STRING(COMPARE EQUAL "sse2" "${SSE_THERE}" SSE2_TRUE)
+     IF (SSE2_TRUE)
+        set(SSE2_FOUND true CACHE BOOL "SSE2 available on host")
+     ELSE (SSE2_TRUE)
+        set(SSE2_FOUND false CACHE BOOL "SSE2 available on host")
+     ENDIF (SSE2_TRUE)
+
+     # /proc/cpuinfo apparently omits sse3 :(
+     STRING(REGEX REPLACE "^.*[^s](sse3).*$" "\\1" SSE_THERE ${CPUINFO})
+     STRING(COMPARE EQUAL "sse3" "${SSE_THERE}" SSE3_TRUE)
+     IF (NOT SSE3_TRUE)
+        STRING(REGEX REPLACE "^.*(T2300).*$" "\\1" SSE_THERE ${CPUINFO})
+        STRING(COMPARE EQUAL "T2300" "${SSE_THERE}" SSE3_TRUE)
+     ENDIF (NOT SSE3_TRUE)
+
+     STRING(REGEX REPLACE "^.*(ssse3).*$" "\\1" SSE_THERE ${CPUINFO})
+     STRING(COMPARE EQUAL "ssse3" "${SSE_THERE}" SSSE3_TRUE)
+     IF (SSE3_TRUE OR SSSE3_TRUE)
+        set(SSE3_FOUND true CACHE BOOL "SSE3 available on host")
+     ELSE (SSE3_TRUE OR SSSE3_TRUE)
+        set(SSE3_FOUND false CACHE BOOL "SSE3 available on host")
+     ENDIF (SSE3_TRUE OR SSSE3_TRUE)
+     IF (SSSE3_TRUE)
+        set(SSSE3_FOUND true CACHE BOOL "SSSE3 available on host")
+     ELSE (SSSE3_TRUE)
+        set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host")
+     ENDIF (SSSE3_TRUE)
+
+     STRING(REGEX REPLACE "^.*(sse4_1).*$" "\\1" SSE_THERE ${CPUINFO})
+     STRING(COMPARE EQUAL "sse4_1" "${SSE_THERE}" SSE41_TRUE)
+     IF (SSE41_TRUE)
+        set(SSE4_1_FOUND true CACHE BOOL "SSE4.1 available on host")
+     ELSE (SSE41_TRUE)
+        set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host")
+     ENDIF (SSE41_TRUE)
+
+     STRING(REGEX REPLACE "^.*(sse4_2).*$" "\\1" SSE_THERE ${CPUINFO})
+     STRING(COMPARE EQUAL "sse4_2" "${SSE_THERE}" SSE42_TRUE)
+     IF (SSE42_TRUE)
+        set(SSE4_2_FOUND true CACHE BOOL "SSE4.2 available on host")
+     ELSE (SSE42_TRUE)
+        set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host")
+     ENDIF (SSE42_TRUE)
+
+  ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Darwin")
+     EXEC_PROGRAM("/usr/sbin/sysctl -n machdep.cpu.features" OUTPUT_VARIABLE
+        CPUINFO)
+
+     STRING(REGEX REPLACE "^.*[^S](SSE2).*$" "\\1" SSE_THERE ${CPUINFO})
+     STRING(COMPARE EQUAL "SSE2" "${SSE_THERE}" SSE2_TRUE)
+     IF (SSE2_TRUE)
+        set(SSE2_FOUND true CACHE BOOL "SSE2 available on host")
+     ELSE (SSE2_TRUE)
+        set(SSE2_FOUND false CACHE BOOL "SSE2 available on host")
+     ENDIF (SSE2_TRUE)
+
+     STRING(REGEX REPLACE "^.*[^S](SSE3).*$" "\\1" SSE_THERE ${CPUINFO})
+     STRING(COMPARE EQUAL "SSE3" "${SSE_THERE}" SSE3_TRUE)
+     IF (SSE3_TRUE)
+        set(SSE3_FOUND true CACHE BOOL "SSE3 available on host")
+     ELSE (SSE3_TRUE)
+        set(SSE3_FOUND false CACHE BOOL "SSE3 available on host")
+     ENDIF (SSE3_TRUE)
+
+     STRING(REGEX REPLACE "^.*(SSSE3).*$" "\\1" SSE_THERE ${CPUINFO})
+     STRING(COMPARE EQUAL "SSSE3" "${SSE_THERE}" SSSE3_TRUE)
+     IF (SSSE3_TRUE)
+        set(SSSE3_FOUND true CACHE BOOL "SSSE3 available on host")
+     ELSE (SSSE3_TRUE)
+        set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host")
+     ENDIF (SSSE3_TRUE)
+
+     STRING(REGEX REPLACE "^.*(SSE4.1).*$" "\\1" SSE_THERE ${CPUINFO})
+     STRING(COMPARE EQUAL "SSE4.1" "${SSE_THERE}" SSE41_TRUE)
+     IF (SSE41_TRUE)
+        set(SSE4_1_FOUND true CACHE BOOL "SSE4.1 available on host")
+     ELSE (SSE41_TRUE)
+        set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host")
+     ENDIF (SSE41_TRUE)
+
+     STRING(REGEX REPLACE "^.*(SSE4.2).*$" "\\1" SSE_THERE ${CPUINFO})
+     STRING(COMPARE EQUAL "SSE4.2" "${SSE_THERE}" SSE42_TRUE)
+     IF (SSE42_TRUE)
+        set(SSE4_2_FOUND true CACHE BOOL "SSE4.2 available on host")
+     ELSE (SSE42_TRUE)
+        set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host")
+     ENDIF (SSE42_TRUE)
+
+  ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Windows")
+     # TODO
+     set(SSE2_FOUND   true  CACHE BOOL "SSE2 available on host")
+     set(SSE3_FOUND   false CACHE BOOL "SSE3 available on host")
+     set(SSSE3_FOUND  false CACHE BOOL "SSSE3 available on host")
+     set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host")
+     set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host")
+  ELSE(CMAKE_SYSTEM_NAME MATCHES "Linux")
+     set(SSE2_FOUND   true  CACHE BOOL "SSE2 available on host")
+     set(SSE3_FOUND   false CACHE BOOL "SSE3 available on host")
+     set(SSSE3_FOUND  false CACHE BOOL "SSSE3 available on host")
+     set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host")
+     set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host")
+  ENDIF(CMAKE_SYSTEM_NAME MATCHES "Linux")
+ENDIF(ARCH MATCHES "i386" OR ARCH MATCHES "x86_64")
+
+if(NOT SSE2_FOUND)
+      MESSAGE(STATUS "Could not find hardware support for SSE2 on this machine.")
+endif(NOT SSE2_FOUND)
+if(NOT SSE3_FOUND)
+      MESSAGE(STATUS "Could not find hardware support for SSE3 on this machine.")
+endif(NOT SSE3_FOUND)
+if(NOT SSSE3_FOUND)
+      MESSAGE(STATUS "Could not find hardware support for SSSE3 on this machine.")
+endif(NOT SSSE3_FOUND)
+if(NOT SSE4_1_FOUND)
+      MESSAGE(STATUS "Could not find hardware support for SSE4.1 on this machine.")
+endif(NOT SSE4_1_FOUND)
+if(NOT SSE4_2_FOUND)
+      MESSAGE(STATUS "Could not find hardware support for SSE4.2 on this machine.")
+endif(NOT SSE4_2_FOUND)
diff --git a/cmake/IgnCodeCoverage.cmake b/cmake/IgnCodeCoverage.cmake
new file mode 100644
index 0000000..6abaeac
--- /dev/null
+++ b/cmake/IgnCodeCoverage.cmake
@@ -0,0 +1,114 @@
+#
+# 2012-01-31, Lars Bilke
+# - Enable Code Coverage
+#
+# 2013-09-17, Joakim Söderberg
+# - Added support for Clang.
+# - Some additional usage instructions.
+#
+# 2017-09-13
+# - Tweaked instructions for ignition libraries
+# - Tweaked function name to avoid name collisions
+#
+# USAGE:
+# 1. Add the following line to your CMakeLists.txt:
+#      INCLUDE(IgnCodeCoverage)
+#
+# 2. Set compiler flags to turn off optimization and enable coverage:
+#    SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+#    SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
+#
+# 3. Use the function IGN_SETUP_TARGET_FOR_COVERAGE to create a custom make target
+#    which runs your test executable and produces a lcov code coverage report:
+#    Example:
+#    IGN_SETUP_TARGET_FOR_COVERAGE(
+#        my_coverage_target  # Name for custom target.
+#        test_driver         # Name of the test driver executable that runs the tests.
+#                            # NOTE! This should always have a ZERO as exit code
+#                            # otherwise the coverage generation will not complete.
+#        coverage            # Name of output directory.
+#        )
+#
+# 4. Build a Coverge build:
+#   cmake -DCMAKE_BUILD_TYPE=Coverage ..
+#   make
+#   make my_coverage_target
+#
+#
+
+# Check prereqs
+FIND_PROGRAM( GCOV_PATH gcov )
+FIND_PROGRAM( LCOV_PATH lcov )
+FIND_PROGRAM( GREP_PATH grep )
+FIND_PROGRAM( GENHTML_PATH genhtml )
+FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests)
+
+IF(NOT GCOV_PATH)
+  MESSAGE(FATAL_ERROR "gcov not found! Aborting...")
+ENDIF() # NOT GCOV_PATH
+
+IF(NOT CMAKE_COMPILER_IS_GNUCXX)
+  # Clang version 3.0.0 and greater now supports gcov as well.
+  MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.")
+
+  IF(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+    MESSAGE(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+  ENDIF()
+ENDIF() # NOT CMAKE_COMPILER_IS_GNUCXX
+
+IF ( NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "Coverage"))
+  MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" )
+ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
+
+
+# Param _targetname     The name of new the custom make target
+# Param _testrunner     The name of the target which runs the tests.
+#						MUST return ZERO always, even on errors.
+#						If not, no coverage report will be created!
+# Param _outputname     lcov output is generated as _outputname.info
+#                       HTML report is generated in _outputname/index.html
+# Optional fourth parameter is passed as arguments to _testrunner
+#   Pass them in list form, e.g.: "-j;2" for -j 2
+FUNCTION(IGN_SETUP_TARGET_FOR_COVERAGE _targetname _testrunner _outputname)
+
+  IF(NOT LCOV_PATH)
+    MESSAGE(FATAL_ERROR "lcov not found! Aborting...")
+  ENDIF() # NOT LCOV_PATH
+
+  IF(NOT GREP_PATH)
+    MESSAGE(FATAL_ERROR "grep not found! Run code coverage on linux or mac.")
+  ENDIF()
+
+  IF(NOT GENHTML_PATH)
+    MESSAGE(FATAL_ERROR "genhtml not found! Aborting...")
+  ENDIF() # NOT GENHTML_PATH
+
+  # Setup target
+  ADD_CUSTOM_TARGET(${_targetname}
+
+    COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info.cleaned
+      ${_outputname}.info
+    # Capturing lcov counters and generating report
+    COMMAND ${LCOV_PATH} -q --no-checksum --directory ${PROJECT_BINARY_DIR}
+      --capture --output-file ${_outputname}.info 2>/dev/null
+    COMMAND ${LCOV_PATH} -q --remove ${_outputname}.info
+      'test/*' '/usr/*' '*_TEST*' --output-file ${_outputname}.info.cleaned
+    COMMAND ${GENHTML_PATH} -q --legend -o ${_outputname}
+      ${_outputname}.info.cleaned
+    COMMAND ${LCOV_PATH} --summary ${_outputname}.info.cleaned 2>&1 | grep "lines" | cut -d ' ' -f 4 | cut -d '%' -f 1 > coverage/lines.txt
+    COMMAND ${LCOV_PATH} --summary ${_outputname}.info.cleaned 2>&1 | grep "functions" | cut -d ' ' -f 4 | cut -d '%' -f 1 > coverage/functions.txt
+    COMMAND ${CMAKE_COMMAND} -E rename ${_outputname}.info.cleaned
+      ${_outputname}.info
+
+    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+    COMMENT "Resetting code coverage counters to zero.\n"
+      "Processing code coverage counters and generating report."
+  )
+
+  # Show info where to find the report
+  ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD
+    COMMAND COMMAND ${LCOV_PATH} -q --zerocounters --directory ${PROJECT_BINARY_DIR};
+    COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report."
+  )
+
+ENDFUNCTION() # IGN_SETUP_TARGET_FOR_COVERAGE
diff --git a/cmake/IgnConfigureBuild.cmake b/cmake/IgnConfigureBuild.cmake
new file mode 100644
index 0000000..2561916
--- /dev/null
+++ b/cmake/IgnConfigureBuild.cmake
@@ -0,0 +1,225 @@
+#.rst
+# IgnBuildProject
+# -------------------
+#
+# ign_configure_build()
+#
+# Configures the build rules of an ignition library project.
+#
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#################################################
+# Configure the build of the ignition project
+# Pass the argument QUIT_IF_BUILD_ERRORS to have this macro quit cmake when the
+# build_errors
+macro(ign_configure_build)
+
+  #============================================================================
+  # Parse the arguments that are passed in
+  set(options QUIT_IF_BUILD_ERRORS)
+  cmake_parse_arguments(ign_configure_build "${options}" "" "" ${ARGN})
+
+  #============================================================================
+  # Examine the build type. If we do not recognize the type, we will generate
+  # an error, so this must come before the error handling.
+  ign_parse_build_type()
+
+  #============================================================================
+  # Ask whether we should make a shared or static library
+  option(BUILD_SHARED_LIBS "Set this to true to generate a shared library (recommended), or false for a static library" ON)
+
+  #============================================================================
+  # Print warnings and errors
+  if(build_warnings)
+    message(STATUS "BUILD WARNINGS")
+    foreach (msg ${build_warnings})
+      message(STATUS ${msg})
+    endforeach ()
+    message(STATUS "END BUILD WARNINGS\n")
+  endif (build_warnings)
+
+  if(build_errors)
+    message(STATUS "BUILD ERRORS: These must be resolved before compiling.")
+    foreach(msg ${build_errors})
+      message(STATUS ${msg})
+    endforeach()
+    message(STATUS " END BUILD ERRORS\n")
+
+    set(error_str "Errors encountered in build. Please see BUILD ERRORS above.")
+
+    if(ign_configure_build_QUIT_IF_BUILD_ERRORS)
+      message(FATAL_ERROR "${error_str}")
+    else()
+      message(WARNING "${error_str}")
+    endif()
+
+  endif()
+
+
+  #============================================================================
+  # If there are no build errors, try building
+  if(NOT build_errors)
+
+    #--------------------------------------
+    # Turn on testing
+    include(CTest)
+    enable_testing()
+
+
+    #--------------------------------------
+    # Set up the compiler flags
+    ign_set_compiler_flags()
+
+
+    #--------------------------------------
+    # Set up the compiler feature flags to help us choose our standard
+    ign_set_cxx_feature_flags()
+
+
+    #--------------------------------------
+    # We want to include both the include directory from the source tree and
+    # also the include directory that's generated in the build folder,
+    # ${PROJECT_BINARY_DIR}, so that headers which are generated via cmake will
+    # be visible to the compiler.
+    include_directories(
+      ${PROJECT_SOURCE_DIR}/include
+      ${PROJECT_BINARY_DIR}/include)
+
+
+    #--------------------------------------
+    # Clear the test results directory
+    execute_process(COMMAND cmake -E remove_directory ${CMAKE_BINARY_DIR}/test_results)
+    execute_process(COMMAND cmake -E make_directory ${CMAKE_BINARY_DIR}/test_results)
+
+
+    #--------------------------------------
+    # Add all the source code directories
+    add_subdirectory(src)
+    add_subdirectory(include)
+    add_subdirectory(test)
+
+
+    #--------------------------------------
+    # If we made it this far, the configuration was successful
+    message(STATUS "Build configuration successful")
+
+  endif()
+
+endmacro()
+
+macro(ign_set_cxx_feature_flags)
+
+  set(IGN_KNOWN_CXX_STANDARDS 11 14)
+
+  set(IGN_CXX_11_FEATURES
+    cxx_alias_templates
+    cxx_alignas
+    cxx_alignof
+    cxx_attributes
+    cxx_auto_type
+    cxx_constexpr
+#    cxx_decltype_incomplete_return_types # Not yet supported in MSVC (as of 2017)
+    cxx_decltype
+    cxx_default_function_template_args
+    cxx_defaulted_functions
+    cxx_defaulted_move_initializers
+    cxx_delegating_constructors
+    cxx_deleted_functions
+    cxx_enum_forward_declarations
+    cxx_explicit_conversions
+    cxx_extended_friend_declarations
+    cxx_extern_templates
+    cxx_final
+    cxx_func_identifier
+    cxx_generalized_initializers
+    cxx_inheriting_constructors
+    cxx_inline_namespaces
+    cxx_lambdas
+    cxx_local_type_template_args
+    cxx_long_long_type
+    cxx_noexcept
+    cxx_nonstatic_member_init
+    cxx_nullptr
+    cxx_override
+    cxx_range_for
+    cxx_raw_string_literals
+    cxx_reference_qualified_functions
+    cxx_right_angle_brackets
+    cxx_rvalue_references
+    cxx_sizeof_member
+    cxx_static_assert
+    cxx_strong_enums
+    cxx_thread_local
+    cxx_trailing_return_types
+    cxx_unicode_literals
+    cxx_unrestricted_unions
+    cxx_user_literals
+    cxx_variadic_macros
+    cxx_variadic_templates)
+
+  set(IGN_CXX_14_FEATURES
+    cxx_attribute_deprecated
+    cxx_binary_literals
+    cxx_contextual_conversions
+    cxx_decltype_auto
+    cxx_digit_separators
+    cxx_generic_lambdas
+    cxx_lambda_init_captures
+#    cxx_relaxed_constexpr # Not yet supported in MSVC (as of 2017)
+    cxx_return_type_deduction
+    cxx_variable_templates)
+
+
+endmacro()
+
+macro(ign_parse_build_type)
+
+  #============================================================================
+  # If a build type is not specified, set it to RelWithDebInfo by default
+  if(NOT CMAKE_BUILD_TYPE)
+    set(CMAKE_BUILD_TYPE "RelWithDebInfo")
+  endif()
+
+  # Convert to uppercase in order to support arbitrary capitalization
+  string(TOUPPER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_UPPERCASE)
+
+  #============================================================================
+  # Set variables based on the build type
+  set(BUILD_TYPE_PROFILE FALSE)
+  set(BUILD_TYPE_RELEASE FALSE)
+  set(BUILD_TYPE_RELWITHDEBINFO FALSE)
+  set(BUILD_TYPE_MINSIZEREL FALSE)
+  set(BUILD_TYPE_DEBUG FALSE)
+
+  if("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "DEBUG")
+    set(BUILD_TYPE_DEBUG TRUE)
+  elseif("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "RELEASE")
+    set(BUILD_TYPE_RELEASE TRUE)
+  elseif("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "RELWITHDEBINFO")
+    set(BUILD_TYPE_RELWITHDEBINFO TRUE)
+  elseif("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "MINSIZEREL")
+    set(BUILD_TYPE_MINSIZEREL TRUE)
+  elseif("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "COVERAGE")
+    include(IgnCodeCoverage)
+    set(BUILD_TYPE_DEBUG TRUE)
+    ign_setup_target_for_coverage(coverage ctest coverage)
+  elseif("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "PROFILE")
+    set(BUILD_TYPE_PROFILE TRUE)
+  else()
+    ign_build_error("CMAKE_BUILD_TYPE [${CMAKE_BUILD_TYPE}] unknown. Valid options are: Debug Release RelWithDebInfo MinSizeRel Profile Check")
+  endif()
+
+endmacro()
diff --git a/cmake/IgnConfigureProject.cmake b/cmake/IgnConfigureProject.cmake
new file mode 100644
index 0000000..a8dc5de
--- /dev/null
+++ b/cmake/IgnConfigureProject.cmake
@@ -0,0 +1,188 @@
+#.rst
+# IgnConfigureProject
+# -------------------
+#
+# ign_configure_project(designation major_version[.minor[.patch[.tweak]]])
+#
+# Sets up an ignition library project. Note that ign_designation should only be
+# the second part of the library name (i.e. it should NOT include the
+# "ignition-" prefix).
+#
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#################################################
+# Initialize the ignition project
+macro(ign_configure_project designation full_version)
+
+  #------------------------------------
+  # Define the expected arguments
+  set(options) # We are not using options yet
+  set(oneValueArgs VERSION_SUFFIX)
+  set(multiValueArgs) # We are not using multiValueArgs yet
+
+  #------------------------------------
+  # Parse the arguments
+  cmake_parse_arguments(ign_configure_project "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+
+  #============================================================================
+  # Extract the major version
+  #============================================================================
+  string(REGEX REPLACE "^([0-9]+).*" "\\1" major_version "${full_version}")
+
+  #============================================================================
+  # Initiate project
+  #============================================================================
+  project(ignition-${designation}${major_version} VERSION ${full_version})
+
+  # Note: The following are automatically defined by project(~) in cmake v3:
+  # PROJECT_VERSION_MAJOR
+  # PROJECT_VERSION_MINOR
+  # PROJECT_VERSION_PATCH
+
+  if(ign_configure_project_VERSION_SUFFIX)
+    set(PROJECT_VERSION_SUFFIX ${ign_configure_project_VERSION_SUFFIX})
+  endif()
+
+
+  #============================================================================
+  # Set project variables
+  #============================================================================
+  set(IGN_DESIGNATION "${designation}")
+
+  set(PROJECT_NAME_NO_VERSION "ignition-${IGN_DESIGNATION}")
+  string(TOLOWER ${PROJECT_NAME_NO_VERSION} PROJECT_NAME_NO_VERSION_LOWER)
+  string(TOUPPER ${PROJECT_NAME_NO_VERSION} PROJECT_NAME_NO_VERSION_UPPER)
+  string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER)
+  string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER)
+  string(TOLOWER ${IGN_DESIGNATION} IGN_DESIGNATION_LOWER)
+  string(TOUPPER ${IGN_DESIGNATION} IGN_DESIGNATION_UPPER)
+
+  set(PROJECT_EXPORT_NAME ${PROJECT_NAME_LOWER})
+  set(PROJECT_LIBRARY_TARGET_NAME ${PROJECT_NAME_LOWER})
+
+  set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR})
+  set(PROJECT_VERSION_FULL
+    ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
+
+  if(PROJECT_VERSION_SUFFIX)
+    set(PROJECT_VERSION_FULL ${PROJECT_VERSION_FULL}~${PROJECT_VERSION_SUFFIX})
+  endif()
+
+  set(PKG_NAME ${PROJECT_NAME_LOWER})
+
+  message(STATUS "${PROJECT_NAME} version ${PROJECT_VERSION_FULL}")
+
+  #============================================================================
+  # Identify the operating system
+  ign_check_os()
+
+  #============================================================================
+  # Create package information
+  ign_setup_packages()
+
+  #============================================================================
+  # Create documentation
+  ign_create_docs()
+
+  #============================================================================
+  # Initialize build errors/warnings
+  # NOTE: We no longer use CACHE for these variables because it was set to
+  # "INTERNAL", making it unnecessary to cache them. As long as this macro is
+  # called from the top-level scope, these variables will effectively be global,
+  # even without putting them in the cache. If this macro is not being called
+  # from the top-level scope, then it is being used incorrectly.
+  set(build_errors "")
+  set(build_warnings "")
+
+
+  #============================================================================
+  # Initialize the list of <PROJECT_NAME>-config.cmake dependencies
+  set(PROJECT_CMAKE_DEPENDENCIES)
+
+  # Initialize the list of <PROJECT_NAME>.pc Requires
+  set(PROJECT_PKGCONFIG_REQUIRES)
+
+  # Initialize the list of <PROJECT_NAME>.pc Requires.private
+  set(PROJECT_PKCONFIG_REQUIRES_PRIVATE)
+
+  # Initialize the list of <PROJECT_NAME>.pc Libs
+  set(PROJECT_PKGCONFIG_LIBS)
+
+  # Initialize the list of <PROJECT_NAME>.pc Libs.private
+  set(PROJECT_PKGCONFIG_LIBS_PRIVATE)
+
+endmacro()
+
+#################################################
+# Check the OS type.
+macro(ign_check_os)
+
+  # CMake does not distinguish Linux from other Unices.
+  string(REGEX MATCH "Linux" PLAYER_OS_LINUX ${CMAKE_SYSTEM_NAME})
+  # Nor *BSD
+  string(REGEX MATCH "BSD" PLAYER_OS_BSD ${CMAKE_SYSTEM_NAME})
+  # Or Solaris. I'm seeing a trend, here
+  string(REGEX MATCH "SunOS" PLAYER_OS_SOLARIS ${CMAKE_SYSTEM_NAME})
+
+  # Windows is easy (for once)
+  if(WIN32)
+    set(PLAYER_OS_WIN TRUE BOOL INTERNAL)
+  endif()
+
+  # Check if it's an Apple OS
+  if(APPLE)
+    # Check if it's OS X or another MacOS (that's got to be pretty unlikely)
+    string(REGEX MATCH "Darwin" PLAYER_OS_OSX ${CMAKE_SYSTEM_NAME})
+    if(NOT PLAYER_OS_OSX)
+      set(PLAYER_OS_MACOS TRUE BOOL INTERNAL)
+    endif()
+  endif()
+
+  # QNX
+  if(QNXNTO)
+    set(PLAYER_OS_QNX TRUE BOOL INTERNAL)
+  endif()
+
+  if(PLAYER_OS_LINUX)
+    message(STATUS "Operating system is Linux")
+  elseif(PLAYER_OS_BSD)
+    message(STATUS "Operating system is BSD")
+  elseif(PLAYER_OS_WIN)
+    message(STATUS "Operating system is Windows")
+  elseif(PLAYER_OS_OSX)
+    message(STATUS "Operating system is Apple MacOS X")
+  elseif(PLAYER_OS_MACOS)
+    message(STATUS "Operating system is Apple MacOS (not OS X)")
+  elseif(PLAYER_OS_QNX)
+    message(STATUS "Operating system is QNX")
+  elseif(PLAYER_OS_SOLARIS)
+    message(STATUS "Operating system is Solaris")
+  else(PLAYER_OS_LINUX)
+    message(STATUS "Operating system is generic Unix")
+  endif()
+
+  #################################################
+  # Check for non-case-sensitive filesystems
+  execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tools/case_sensitive_filesystem
+                  RESULT_VARIABLE FILESYSTEM_CASE_SENSITIVE_RETURN)
+  if (${FILESYSTEM_CASE_SENSITIVE_RETURN} EQUAL 0)
+    set(FILESYSTEM_CASE_SENSITIVE TRUE)
+  else()
+    set(FILESYSTEM_CASE_SENSITIVE FALSE)
+  endif()
+
+endmacro()
diff --git a/cmake/IgnCreateDocs.cmake b/cmake/IgnCreateDocs.cmake
new file mode 100644
index 0000000..b0fb83f
--- /dev/null
+++ b/cmake/IgnCreateDocs.cmake
@@ -0,0 +1,50 @@
+#.rst
+# IgnCreatePackage
+# ----------------
+#
+# ign_create_docs
+#
+# Creates documentation for an ignition library project.
+#
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#################################################
+# Create documentation information
+macro(ign_create_docs)
+
+  #--------------------------------------
+  # Traverse the doc directory
+  add_subdirectory(doc)
+
+  #--------------------------------------
+  # Configure documentation uploader
+  configure_file("${IGNITION_CMAKE_DIR}/upload_doc.sh.in"
+    ${CMAKE_BINARY_DIR}/upload_doc.sh @ONLY)
+
+  #--------------------------------------
+  # If we're configuring only to build docs, stop here
+  if (DOC_ONLY)
+    message(WARNING "Configuration was done in DOC_ONLY mode."
+    " You can build documentation (make doc), but nothing else.")
+    return()
+  endif()
+
+  #--------------------------------------
+  # Create man pages
+  include(IgnRonn2Man)
+  ign_add_manpage_target()
+
+endmacro()
diff --git a/cmake/IgnImportTarget.cmake b/cmake/IgnImportTarget.cmake
new file mode 100644
index 0000000..3b9cdd7
--- /dev/null
+++ b/cmake/IgnImportTarget.cmake
@@ -0,0 +1,121 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# ign_import_target(<package> [TARGET_NAME <target_name>])
+#
+# This macro will create an imported target based on the variables pertaining
+# to <package>, such as <package>_LIBRARIES, <package>_INCLUDE_DIRS, and
+# <package>_CFLAGS. Optionally, you can provide TARGET_NAME followed by a
+# string, which will then be used as the name of the imported target. If
+# TARGET_NAME is not provided, the name of the imported target will default to
+# <package>::<package>.
+#
+macro(ign_import_target package)
+
+  #------------------------------------
+  # Define the expected arguments
+  set(options) # We are not using options yet
+  set(oneValueArgs "TARGET_NAME")
+  set(multiValueArgs) # We are not using multiValueArgs yet
+
+  #------------------------------------
+  # Parse the arguments
+  cmake_parse_arguments(ign_import_target "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+  #------------------------------------
+  # Check if a target name has been provided, otherwise use
+  # ${package}::{$package} as the target name.
+  if(ign_import_target_TARGET_NAME)
+    set(target_name ${ign_import_target_TARGET_NAME})
+  else()
+    set(target_name ${package}::${package})
+  endif()
+
+
+  #------------------------------------
+  # Link against this "imported" target by saying
+  # target_link_libraries(mytarget package::package), instead of linking
+  # against the variable package_LIBRARIES with the old-fashioned
+  # target_link_libraries(mytarget ${package_LIBRARIES}
+  add_library(${target_name} IMPORTED SHARED)
+
+  if(${package}_LIBRARIES)
+    _ign_sort_libraries(${target_name} ${${package}_LIBRARIES})
+  endif()
+
+  if(${package}_LIBRARIES)
+    set_target_properties(${target_name} PROPERTIES
+      INTERFACE_LINK_LIBRARIES "${${package}_LIBRARIES}")
+  endif()
+
+  foreach(${package}_inc ${${package}_INCLUDE_DIRS})
+    set_target_properties(${target_name} PROPERTIES
+      INTERFACE_INCLUDE_DIRECTORIES "${${package}_inc}")
+  endforeach()
+
+  if(${package}_CFLAGS)
+    set_target_properties(${target_name} PROPERTIES
+      INTERFACE_COMPILE_OPTIONS "${${package}_CFLAGS}")
+  endif()
+
+  # What about linker flags? Is there no target property for that?
+
+endmacro()
+
+# This is an awkward hack to give the package both an IMPORTED_LOCATION and
+# a set of INTERFACE_LIBRARIES in the event that PkgConfig returns multiple
+# libraries for this package. It seems that IMPORTED_LOCATION cannot support
+# specifying multiple libraries, so if we have multiple libraries, we need to
+# pass them into INTERFACE_LINK_LIBRARIES. However, if IMPORTED_LOCATION is
+# missing from the target, the dependencies do not get configured correctly by
+# the generator expressions, and the build system will try to link to a nonsense
+# garbage file.
+#
+# TODO: Figure out if there is a better way to fill in the various library
+# properties of an imported target.
+function(_ign_sort_libraries target_name first_lib)
+
+  if(MSVC)
+    # Note: For MSVC, we only care about the "import library" which is the
+    # library ending in *.lib. The linker only needs to be told where the
+    # *.lib library is. The dynamic library (*.dll) only needs to be visible
+    # to the program at run-time, not at compile or link time. Furthermore,
+    # find_library on Windows only looks for *.lib files, so we expect that
+    # results of the form package_LIBRARIES will contain *.lib files when
+    # running on Windows. IMPORTED_IMPLIB is the target property that
+    # indicates the "import library" of an "imported target", so that is
+    # the property that will fill in first and foremost.
+    #
+    # TODO: How does MinGW handle libraries?
+    set_target_properties(${target_name} PROPERTIES
+      IMPORTED_IMPLIB "${first_lib}")
+  else()
+    set_target_properties(${target_name} PROPERTIES
+      IMPORTED_LOCATION "${first_lib}")
+  endif()
+
+  foreach(extra_lib ${ARGN})
+    set_target_properties(${target_name} PROPERTIES
+      INTERFACE_LINK_LIBRARIES "${extra_lib}")
+  endforeach()
+
+  get_target_property(ill ${target_name} INTERFACE_LINK_LIBRARIES)
+  set_target_properties(${target_name}
+    PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES ${ill})
+  set_target_properties(${target_name}
+    PROPERTIES IMPORTED_LINK_DEPENDENT_LIBRARIES ${ill})
+
+endfunction()
diff --git a/cmake/IgnPackaging.cmake b/cmake/IgnPackaging.cmake
new file mode 100644
index 0000000..6ad2ce7
--- /dev/null
+++ b/cmake/IgnPackaging.cmake
@@ -0,0 +1,268 @@
+#.rst
+# IgnPackaging
+# ----------------
+#
+# ign_setup_packages
+#
+# Sets up package information for an ignition library project.
+#
+# ign_create_package
+#
+# Creates a package for an ignition library project
+#
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#################################################
+# Set up package information
+macro(ign_setup_packages)
+
+  #============================================================================
+  # Use GNUInstallDirs to get canonical paths.
+  # We use this filesystem style on Windows as well, because (quite frankly)
+  # Windows does not seem to have any sensible convention of its own for
+  # installing development libraries. (If anyone is aware of a widely accepted
+  # convention for where to install development libraries on Windows, please
+  # correct this.)
+  include(GNUInstallDirs)
+
+  #============================================================================
+  #Find available package generators
+
+  # DEB
+  if("${CMAKE_SYSTEM}" MATCHES "Linux")
+    find_program(DPKG_PROGRAM dpkg)
+    if(EXISTS ${DPKG_PROGRAM})
+      list(APPEND CPACK_GENERATOR "DEB")
+    endif(EXISTS ${DPKG_PROGRAM})
+
+    find_program(RPMBUILD_PROGRAM rpmbuild)
+  endif()
+
+  list(APPEND CPACK_SOURCE_GENERATOR "TBZ2")
+  list(APPEND CPACK_SOURCE_GENERATOR "ZIP")
+  list(APPEND CPACK_SOURCE_IGNORE_FILES "TODO;\.hg/;\.sw.$;/build/;\.hgtags;\.hgignore;appveyor\.yml;\.travis\.yml;codecov\.yml")
+
+  include(InstallRequiredSystemLibraries)
+
+  #execute_process(COMMAND dpkg --print-architecture _NPROCE)
+  set(DEBIAN_PACKAGE_DEPENDS "")
+
+  set(RPM_PACKAGE_DEPENDS "")
+
+  set(PROJECT_CPACK_CFG_FILE "${PROJECT_BINARY_DIR}/cpack_options.cmake")
+
+  #============================================================================
+  # Set CPack variables
+  set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION_FULL}")
+  set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
+  set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
+  set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
+
+  if(CPACK_GENERATOR)
+    message(STATUS "Found CPack generators: ${CPACK_GENERATOR}")
+
+    configure_file("${IGNITION_CMAKE_DIR}/cpack_options.cmake.in"
+      ${PROJECT_CPACK_CFG_FILE} @ONLY)
+
+    set(CPACK_PROJECT_CONFIG_FILE ${PROJECT_CPACK_CFG_FILE})
+    include(CPack)
+  endif()
+
+  #============================================================================
+  # If we're configuring only to package source, stop here
+  if(PACKAGE_SOURCE_ONLY)
+    message(WARNING "Configuration was done in PACKAGE_SOURCE_ONLY mode."
+    "You can build a tarball (make package_source), but nothing else.")
+    return()
+  endif()
+
+  #============================================================================
+  # Developer's option to cache PKG_CONFIG_PATH and
+  # LD_LIBRARY_PATH for local installs
+  if(PKG_CONFIG_PATH)
+    set(ENV{PKG_CONFIG_PATH} ${PKG_CONFIG_PATH}:$ENV{PKG_CONFIG_PATH})
+  endif()
+
+  if(LD_LIBRARY_PATH)
+    set(ENV{LD_LIBRARY_PATH} ${LD_LIBRARY_PATH}:$ENV{LD_LIBRARY_PATH})
+  endif()
+
+  #============================================================================
+  # Set up installation directories
+  set(IGN_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}")
+  set(IGN_INCLUDE_INSTALL_DIR_POSTFIX "ignition/${IGN_DESIGNATION}${PROJECT_VERSION_MAJOR}")
+  set(IGN_INCLUDE_INSTALL_DIR_FULL    "${IGN_INCLUDE_INSTALL_DIR}/${IGN_INCLUDE_INSTALL_DIR_POSTFIX}")
+  set(IGN_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
+  set(IGN_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR})
+
+  #============================================================================
+  # Handle the user's RPATH setting
+  option(USE_FULL_RPATH "Turn on to enable the full RPATH" OFF)
+  if(USE_FULL_RPATH)
+    # use, i.e. don't skip the full RPATH for the build tree
+    set(CMAKE_SKIP_BUILD_RPATH FALSE)
+
+    # when building, don't use the install RPATH already
+    # (but later on when installing)
+    set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
+
+    set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${IGN_LIB_INSTALL_DIR}")
+
+    # add the automatically determined parts of the RPATH
+    # which point to directories outside the build tree to the install RPATH
+    set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+
+    # the RPATH to be used when installing, but only if its not a system directory
+    list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${IGN_LIB_INSTALL_DIR}" isSystemDir)
+    if("${isSystemDir}" STREQUAL "-1")
+      set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${IGN_LIB_INSTALL_DIR}")
+    endif("${isSystemDir}" STREQUAL "-1")
+  endif()
+
+  #============================================================================
+  # Add uninstall target
+  configure_file(
+    "${IGNITION_CMAKE_DIR}/cmake_uninstall.cmake.in"
+    "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+    IMMEDIATE @ONLY)
+  add_custom_target(uninstall
+    "${CMAKE_COMMAND}" -P
+    "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
+
+endmacro()
+
+macro(ign_create_packages)
+
+  #============================================================================
+  # Configure the typical package configs for this project
+  ign_create_pkgconfig()
+
+  #============================================================================
+  # Configure the cmake package for this project
+  ign_create_cmake_package()
+
+  #============================================================================
+  # Load platform-specific build hooks if present.
+  ign_load_build_hooks()
+
+  #============================================================================
+  # Tell the user what their settings are
+  message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
+  message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}")
+
+endmacro()
+
+
+#################################################
+# Create a pkgconfig file for your ignition project, and install it.
+# ign_create_pkgconfig()
+function(ign_create_pkgconfig)
+
+  set(pkgconfig_input "${IGNITION_CMAKE_DIR}/pkgconfig/ignition.pc.in")
+  set(pkgconfig_output "${CMAKE_BINARY_DIR}/${PKG_NAME}.pc")
+  configure_file(${pkgconfig_input} ${pkgconfig_output} @ONLY)
+
+  install(
+    FILES ${pkgconfig_output}
+    DESTINATION ${IGN_LIB_INSTALL_DIR}/pkgconfig
+    COMPONENT pkgconfig)
+
+endfunction()
+
+#################################################
+# Make the cmake config files for this project
+function(ign_create_cmake_package)
+
+  # Set configuration arguments
+  set(ign_config_input "${IGNITION_CMAKE_DIR}/ignition-config.cmake.in")
+  set(ign_config_output "${PROJECT_NAME_LOWER}-config.cmake")
+  set(ign_version_output "${PROJECT_NAME_LOWER}-config-version.cmake")
+  set(ign_targets_output "${PROJECT_NAME_LOWER}-targets.cmake")
+  set(ign_config_install_dir "${IGN_LIB_INSTALL_DIR}/cmake/${PROJECT_NAME_LOWER}")
+
+  # Configure the package config file. It will be installed to
+  # "[lib]/cmake/ignition-<project><major_version>/" where [lib] is the library
+  # installation directory.
+  configure_package_config_file(
+    ${ign_config_input}
+    ${ign_config_output}
+    INSTALL_DESTINATION ${ign_config_install_dir}
+    PATH_VARS IGN_LIB_INSTALL_DIR IGN_INCLUDE_INSTALL_DIR_FULL)
+
+  # Use write_basic_package_version_file to generate a ConfigVersion file that
+  # allow users of the library to specify the API or version to depend on
+  write_basic_package_version_file(
+    ${CMAKE_CURRENT_BINARY_DIR}/${ign_version_output}
+    VERSION "${PROJECT_VERSION_FULL}"
+    COMPATIBILITY SameMajorVersion)
+
+  # Install the configuration files to the configuration installation directory
+  install(
+    FILES
+      ${CMAKE_CURRENT_BINARY_DIR}/${ign_config_output}
+      ${CMAKE_CURRENT_BINARY_DIR}/${ign_version_output}
+    DESTINATION ${ign_config_install_dir}
+    COMPONENT cmake)
+
+  # Create *-targets.cmake file for build directory
+  export(
+    EXPORT ${PROJECT_EXPORT_NAME}
+    FILE ${CMAKE_BINARY_DIR}/${ign_targets_output}
+    # We add a namespace that ends with a :: to the name of the exported target.
+    # This is so consumers of the project can call
+    #     find_package(ignition-<project>)
+    #     target_link_libraries(consumer_project ignition-<project>::ignition-<project>)
+    # and cmake will understand that the consumer is asking to link the imported
+    # target "ignition-<project>" to their "consumer_project" rather than asking
+    # to link a library named "ignition-<project>". In other words, when
+    # target_link_libraries is given a name that contains double-colons (::) it
+    # will never mistake it for a library name, and it will throw an error if
+    # it cannot find a target with the given name.
+    #
+    # The advantage of linking against a target rather than a library is that
+    # you will automatically link against all the dependencies of that target.
+    # This also helps us create find-config files that are relocatable.
+    NAMESPACE ${PROJECT_EXPORT_NAME}::)
+
+  # Install *-targets.cmake file
+  install(
+    EXPORT ${PROJECT_EXPORT_NAME}
+    DESTINATION ${ign_config_install_dir}
+    FILE ${ign_targets_output}
+    # See explanation above for NAMESPACE
+    NAMESPACE ${PROJECT_EXPORT_NAME}::)
+
+endfunction()
+
+#################################################
+# Make the cmake config files for this project
+# Pass an argument to specify the directory where the CMakeLists.txt for the
+#   build hooks is located. If no argument is provided, we default to:
+#   ${PROJECT_SOURCE_DIR}/packager-hooks
+function(ign_load_build_hooks)
+
+  if(ARGV0)
+    set(hook_dir ${ARGV0})
+  else()
+    set(hook_dir "${PROJECT_SOURCE_DIR}/cmake/packager-hooks")
+  endif()
+
+  if(EXISTS ${hook_dir}/CMakeLists.txt)
+    message(STATUS "Loading packager build hooks from ${hook_dir}")
+    add_subdirectory(${hook_dir})
+  endif()
+
+endfunction()
diff --git a/cmake/IgnPkgConfig.cmake b/cmake/IgnPkgConfig.cmake
new file mode 100644
index 0000000..adee5c3
--- /dev/null
+++ b/cmake/IgnPkgConfig.cmake
@@ -0,0 +1,113 @@
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+########################################
+# An alternative to pkg_check_modules that creates an "imported target" which
+# helps us to make relocatable packages.
+#
+# NOTE: This macro assumes that pkgconfig is the only means by which you will be
+#       searching for the package. If you intend to continue searching in the
+#       event that pkgconfig fails (or is unavailable), then you should instead
+#       call ign_pkg_check_modules_quiet(~).
+macro(ign_pkg_check_modules package)
+
+  ign_pkg_check_modules_quiet(${package} ${ARGN})
+
+  if(NOT PKG_CONFIG_FOUND)
+    status(WARNING "The package [${package}] requires pkg-config in order to be found. "
+                   "Please install pkg-config so we can search for that package.")
+  endif()
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(
+    ${package}
+    REQUIRED_VARS ${package}_FOUND)
+
+endmacro()
+
+# This is an alternative to ign_pkg_check_modules(~) which you can use if you
+# have an alternative way to look for the package if pkgconfig is not available
+# or cannot find the requested package. This will still setup the pkgconfig
+# variables for you, whether or not pkgconfig is available.
+macro(ign_pkg_check_modules_quiet package)
+
+  find_package(PkgConfig QUIET)
+
+  set(${package}_PKGCONFIG_ENTRY "${ARGN}")
+  set(${package}_PKGCONFIG_TYPE PROJECT_PKGCONFIG_REQUIRES)
+
+  if(PKG_CONFIG_FOUND)
+
+    pkg_check_modules(${package} ${ARGN})
+
+    # TODO: When we require cmake-3.6+, we should remove this procedure and just
+    #       use the plain pkg_check_modules, which provides an option called
+    #       IMPORTED_TARGET that will create the imported targets the way we do
+    #       here.
+    if(${package}_FOUND AND NOT TARGET ${package}::${package})
+
+      # pkg_check_modules will put ${package}_FOUND into the CACHE, which would
+      # prevent our FindXXX.cmake script from being entered the next time cmake
+      # is run by a dependent project. This is a problem for us because we
+      # produce an imported target which gets wiped out and needs to recreated
+      # between runs.
+      #
+      # TODO: Investigate if there is a more conventional solution to this
+      # problem. Perhaps the cmake-3.6 version of pkg_check_modules has a
+      # better solution.
+      unset(${package}_FOUND CACHE)
+      set(${package}_FOUND true)
+
+      # For some reason, pkg_check_modules does not provide complete paths to the
+      # libraries it returns, even though find_package is conventionally supposed
+      # to provide complete library paths. Having only the library name is harmful
+      # to the ign_create_imported_target macro, so we will change the variable to
+      # give it complete paths.
+      #
+      # TODO: How would we deal with multiple modules that are in different
+      # directories? How does cmake-3.6+ handle that situation?
+      _ign_pkgconfig_find_libraries(
+        ${package}_LIBRARIES
+        ${package}
+        "${${package}_LIBRARIES}"
+        "${${package}_LIBRARY_DIRS}")
+
+      include(IgnImportTarget)
+      ign_import_target(${package})
+
+    endif()
+
+  endif()
+
+endmacro()
+
+# Based on discussion here: https://cmake.org/Bug/view.php?id=15804
+# and a patch written by Sam Thursfield
+function(_ign_pkgconfig_find_libraries output_var package library_names library_dirs)
+
+  foreach(libname ${library_names})
+
+    find_library(
+      ${package}_LIBRARY_${libname}
+      ${libname}
+      PATHS ${library_dirs})
+
+    list(APPEND library_paths "${${package}_LIBRARY_${libname}}")
+
+  endforeach()
+
+  set(${output_var} ${library_paths} PARENT_SCOPE)
+
+endfunction()
diff --git a/cmake/IgnRonn2Man.cmake b/cmake/IgnRonn2Man.cmake
new file mode 100644
index 0000000..ea44500
--- /dev/null
+++ b/cmake/IgnRonn2Man.cmake
@@ -0,0 +1,64 @@
+#
+# Based on work of Emmanuel Roullit <emmanuel at netsniff-ng.org>
+# Copyright 2009, 2012 Emmanuel Roullit.
+# Subject to the GPL, version 2.
+#
+
+# 2017-09-13
+# - Tweaked macro name to avoid name collisions
+#
+
+MACRO(IGN_ADD_MANPAGE_TARGET)
+  # It is not possible add a dependency to target 'install'
+  # Run hard-coded 'make man' when 'make install' is invoked
+  INSTALL(CODE "EXECUTE_PROCESS(COMMAND make man)")
+  ADD_CUSTOM_TARGET(man)
+ENDMACRO(IGN_ADD_MANPAGE_TARGET)
+
+FIND_PROGRAM(RONN ronn)
+FIND_PROGRAM(GZIP gzip)
+
+IF (NOT RONN OR NOT GZIP)
+  IF (NOT RONN)
+    IGN_BUILD_WARNING ("ronn not found, manpages won't be generated")
+  ENDIF(NOT RONN)
+  IF (NOT GZIP)
+    IGN_BUILD_WARNING ("gzip not found, manpages won't be generated")
+  ENDIF(NOT GZIP)
+  # empty macro
+  MACRO(manpage MANFILE)
+  ENDMACRO(manpage)
+  SET (MANPAGES_SUPPORT FALSE)
+ELSE (NOT RONN OR NOT GZIP)
+  MESSAGE (STATUS "Looking for ronn to generate manpages - found")
+  SET (MANPAGES_SUPPORT TRUE)
+
+  MACRO(manpage RONNFILE SECTION)
+    SET(RONNFILE_FULL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${RONNFILE})
+
+    ADD_CUSTOM_COMMAND(
+      OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}
+      DEPENDS ${RONNFILE}
+      COMMAND ${RONN}
+         ARGS -r --pipe ${RONNFILE_FULL_PATH}.${SECTION}.ronn
+         > ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}
+    )
+
+    ADD_CUSTOM_COMMAND(
+      OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz
+      DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}
+      COMMAND ${GZIP} -c ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}
+        > ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz
+    )
+
+    SET(MANPAGE_TARGET "man-${RONNFILE}")
+
+    ADD_CUSTOM_TARGET(${MANPAGE_TARGET} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz)
+    ADD_DEPENDENCIES(man ${MANPAGE_TARGET})
+
+    INSTALL(
+      FILES ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz
+      DESTINATION share/man/man${SECTION}
+    )
+  ENDMACRO(manpage RONNFILE SECTION)
+ENDIF(NOT RONN OR NOT GZIP)
diff --git a/cmake/IgnSetCompilerFlags.cmake b/cmake/IgnSetCompilerFlags.cmake
new file mode 100644
index 0000000..ee9e3cf
--- /dev/null
+++ b/cmake/IgnSetCompilerFlags.cmake
@@ -0,0 +1,341 @@
+#.rst
+# IgnSetCompilerFlags
+# -------------------
+#
+# ign_set_compiler_flags()
+#
+# Sets up compiler flags for an ignition library project
+#
+#===============================================================================
+# Copyright (C) 2017 Open Source Robotics Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#################################################
+# Set up compiler flags
+macro(ign_set_compiler_flags)
+
+  option(USE_IGN_RECOMMENDED_FLAGS "Build project using the compiler flags recommended by the ignition developers" ON)
+
+  if(MSVC)
+    ign_setup_msvc()
+  elseif(UNIX)
+    ign_setup_unix()
+  endif()
+
+  if(APPLE)
+    ign_setup_apple()
+  endif()
+
+  # Check if we are compiling with Clang and cache it
+  if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+    set(CLANG true)
+  endif()
+
+  # Check if we are compiling with GCC and cache it
+  if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+    set(GCC true)
+  endif()
+
+  # GCC and Clang use many of the same compilation flags, so it might be useful
+  # to have a variable that indicates if one of them is being used.
+  if(GCC OR CLANG)
+    set(GCC_OR_CLANG true)
+  endif()
+
+  if(GCC_OR_CLANG)
+
+    if(USE_IGN_RECOMMENDED_FLAGS)
+      ign_setup_gcc_or_clang()
+    endif()
+
+    option(USE_HOST_SSE_FLAGS "Explicitly use compiler flags to indicate the SSE version of the host machine" TRUE)
+    if(USE_HOST_SSE_FLAGS)
+      ign_set_sse_flags()
+    endif()
+
+  endif()
+
+endmacro()
+
+#################################################
+# Configure settings for Unix
+macro(ign_setup_unix)
+
+  find_program(CMAKE_UNAME uname /bin /usr/bin /usr/local/bin )
+  if(CMAKE_UNAME)
+    exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_SYSTEM_PROCESSOR)
+    set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR} CACHE INTERNAL
+        "processor type (i386 and x86_64)")
+    if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
+      set(IGN_ADD_fPIC_TO_LIBRARIES true)
+    endif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
+  endif(CMAKE_UNAME)
+
+endmacro()
+
+#################################################
+macro(ign_setup_apple)
+
+  # NOTE MacOSX provides different system versions than CMake is parsing.
+  #      The following table lists the most recent OSX versions
+  #     9.x.x = Mac OSX Leopard (10.5)
+  #    10.x.x = Mac OSX Snow Leopard (10.6)
+  #    11.x.x = Mac OSX Lion (10.7)
+  #    12.x.x = Mac OSX Mountain Lion (10.8)
+  if(${CMAKE_SYSTEM_VERSION} LESS 10)
+    add_definitions(-DMAC_OS_X_VERSION=1050)
+  elseif(${CMAKE_SYSTEM_VERSION} GREATER 10 AND ${CMAKE_SYSTEM_VERSION} LESS 11)
+    add_definitions(-DMAC_OS_X_VERSION=1060)
+  elseif(${CMAKE_SYSTEM_VERSION} GREATER 11 AND ${CMAKE_SYSTEM_VERSION} LESS 12)
+    add_definitions(-DMAC_OS_X_VERSION=1070)
+  elseif(${CMAKE_SYSTEM_VERSION} GREATER 12 OR ${CMAKE_SYSTEM_VERSION} EQUAL 12)
+    add_definitions(-DMAC_OS_X_VERSION=1080)
+    # Use libc++ on Mountain Lion (10.8)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+  else()
+    add_definitions(-DMAC_OS_X_VERSION=0)
+  endif()
+
+  set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-undefined -Wl,dynamic_lookup")
+
+endmacro()
+
+#################################################
+# Set up compilation flags for GCC or Clang
+macro(ign_setup_gcc_or_clang)
+
+  ign_filter_valid_compiler_options(
+    CUSTOM_ALL_FLAGS
+        -Wall -Wextra -Wno-long-long -Wno-unused-value -Wfloat-equal
+        -Wshadow -Winit-self -Wswitch-default -Wmissing-include-dirs -pedantic
+        -fvisibility)
+
+  # -ggdb3: Produce comprehensive debug information that can be utilized by gdb
+  set(CUSTOM_DEBUG_FLAGS "-ggdb3")
+
+  # We use the default flags for Release
+  set(CUSTOM_RELEASE_FLAGS "")
+
+  # -UNDEBUG: Undefine the NDEBUG symbol so that assertions get triggered in
+  #           RelWithDebInfo mode
+  # NOTE: Always make -UNDEBUG the first flag in this list so that it appears
+  #       immiediately after cmake's automatically provided -DNDEBUG flag.
+  #       Keeping them next to each other should make it more clear that the
+  #       -DNDEBUG flag is being canceled out.
+  set(CUSTOM_RELWITHDEBINFO_FLAGS "-UNDEBUG")
+
+  # We use the default flags for MinSizeRel
+  set(CUSTOM_MINSIZEREL_FLAGS "")
+
+  # -fno-omit-frame-pointer: TODO Why do we use this?
+  # -g: Produce debug information
+  # -pg: Produce information that is helpful for the gprof profiling  tool
+  set(CUSTOM_PROFILE_FLAGS "-fno-omit-frame-pointer -g -pg")
+
+  # -g: Produce debug information.
+  # -O0: Do absolutely no performance optimizations and reduce compilation time.
+  # -Wformat=2: Print extra warnings for string formatting functions.
+  # --coverage: Tell the compiler that we want our build to be instrumented for
+  #             coverage analysis.
+  # -fno-inline: Prevent the compiler from inlining functions. Inlined functions
+  #              may confuse the coverage analysis.
+  set(CUSTOM_C_COVERAGE_FLAGS "-g -O0 -Wformat=2 --coverage -fno-inline")
+
+  set(CUSTOM_CXX_COVERAGE_FLAGS "${CUSTOM_C_COVERAGE_FLAGS}")
+
+  # We add these flags depending on whether the compiler can support them,
+  # because they cause errors when compiling with Clang.
+  # -fno-elide-constructors: Prevent the compiler from eliding constructors.
+  #                          Elision may confuse the coverage analysis.
+  # -fno-default-inline: Prevent class members that are defined inside of their
+  #                      class definition from automatically being marked as
+  #                      inline functions.
+  #                      ...TODO: Is this redundant with -fno-inline?
+  # -fno-implicit-inline-templates: TODO: Why do we use this?
+  ign_filter_valid_compiler_options(
+    CUSTOM_CXX_COVERAGE_FLAGS
+        -fno-elide-constructors
+        -fno-default-inline
+        -fno-implicit-inline-templates)
+
+
+  # NOTE We do not use the CACHE argument when appending flags to these
+  # variables, because appending to the CACHE will make these variables grow
+  # with redundant flags each time cmake is run. By not using CACHE, we create
+  # "local" copies of each of these variables, so they will not be preserved
+  # between runs of cmake. However, since these "local" variables are created in
+  # the top-level scope, they will be visible to all subdirectories in our
+  # filesystem, making them effectively global.
+
+  # NOTE These flags are being specified in a very particular order. First, we
+  # specify the original set of flags, then we specify the set of flags which
+  # are being passed to all build types, then we specify the set of flags which
+  # are specific to each build type. When contradictory flags are given to a
+  # compiler, whichever flag was specified last gets precedence. Therefore, we
+  # want the flags that we're passing in now to have precedence over the
+  # original flags for each build type, and we want the flags that are specific
+  # to each build type to have precedence over the flags that are passed to all
+  # build types, to make sure that each build type can customize its flags
+  # without any conflicts.
+
+
+  # cmake automatically provides -g for *_FLAGS_DEBUG
+  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${CUSTOM_ALL_FLAGS} ${CUSTOM_DEBUG_FLAGS}")
+  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${CUSTOM_ALL_FLAGS} ${CUSTOM_DEBUG_FLAGS}")
+
+
+  # cmake automatically provides -O3 and -DNDEBUG for *_FLAGS_RELEASE
+  set(CMAKE_C_FLAGS_RELEASE   "${CMAKE_C_FLAGS_RELEASE} ${CUSTOM_RELEASE_FLAGS} ${CUSTOM_ALL_FLAGS}")
+  set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${CUSTOM_ALL_FLAGS} ${CUSTOM_RELEASE_FLAGS}")
+
+
+  # cmake automatically provides -g, -O2, and -DNDEBUG for *_FLAGS_RELWITHDEBINFO
+  set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${CUSTOM_ALL_FLAGS} ${CUSTOM_RELWITHDEBINFO_FLAGS}")
+  set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${CUSTOM_ALL_FLAGS} ${CUSTOM_RELWITHDEBINFO_FLAGS}")
+
+
+  # cmake automatically provides -Os and -DNDEBUG for *_FLAGS_MINSIZEREL
+  set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} ${CUSTOM_ALL_FLAGS} ${CUSTOM_MINSIZEREL_FLAGS}")
+  set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${CUSTOM_ALL_FLAGS} ${CUSTOM_MINSIZEREL_FLAGS}")
+
+
+  # PROFILE is a custom build type, not automatically provided by cmake
+  set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_PROFILE} ${CUSTOM_ALL_FLAGS} ${CUSTOM_PROFILE_FLAGS}")
+  set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_PROFILE} ${CUSTOM_ALL_FLAGS} ${CUSTOM_PROFILE_FLAGS}")
+
+
+  # COVERAGE is a custom build type, not automatically provided by cmake
+  set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE} ${CUSTOM_ALL_FLAGS} ${CUSTOM_C_COVERAGE_FLAGS}")
+  set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} ${CUSTOM_ALL_FLAGS} ${CUSTOM_CXX_COVERAGE_FLAGS}")
+
+
+  # NOTE: Leave CMAKE_C_FLAGS and CMAKE_CXX_FLAGS blank, because those will
+  # be appended to all build configurations.
+
+endmacro()
+
+#################################################
+# Identify what type of Streaming SIMD Extension is being used by the system and
+# then set the compiler's SSE flags appropriately.
+macro(ign_set_sse_flags)
+
+  message(STATUS "\n-- Searching for host SSE information")
+  include(IgnCheckSSE)
+
+  if(SSE2_FOUND)
+    add_compile_options(-msse -msse2)
+    if (NOT APPLE)
+      add_compile_options(-mfpmath=sse)
+      message(STATUS "SSE2 found")
+    endif()
+  endif()
+
+  if(SSE3_FOUND)
+    add_compile_options(-msse3)
+    message(STATUS "SSE3 found")
+  endif()
+  if (SSSE3_FOUND)
+    add_compile_options(-mssse3)
+  endif()
+
+  if (SSE4_1_FOUND OR SSE4_2_FOUND)
+    if (SSE4_1_FOUND)
+      add_compile_options(-msse4.1)
+      message(STATUS "SSE4.1 found")
+    endif()
+    if (SSE4_2_FOUND)
+      add_compile_options(-msse4.2)
+      message(STATUS "SSE4.2 found")
+    endif()
+  else()
+    message(STATUS "SSE4 disabled.\n--")
+  endif()
+
+endmacro()
+
+#################################################
+# Set up compilation flags for Microsoft Visual Studio/C++
+macro(ign_setup_msvc)
+
+  # Reduce overhead by ignoring unnecessary Windows headers
+  add_definitions(-DWIN32_LEAN_AND_MEAN)
+
+  # Use the dynamically loaded run-time library in Windows by default. The
+  # dynamically loaded run-time reduces the binary size and automatically
+  # benefits from updates to the run-time library without the need to recompile.
+  # It also allows us to avoid a "One Definition Rule" violation when linking
+  # with libraries that also use the dynamically loaded run-time.
+  set(BUILD_SHARED_LIBS TRUE)
+  set(IGN_RUNTIME_LIBRARY "/MD" CACHE STRING "Visual Studio Runtime Library Flag")
+  set_property(CACHE IGN_RUNTIME_LIBRARY PROPERTY STRINGS /MD /MT)
+
+  # Don't pull in the Windows min/max macros
+  add_definitions(-DNOMINMAX)
+
+  if (MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+    # Not needed if a proper cmake generator (-G "...Win64") is passed
+    # to cmake. Enable as a second measure to work around bug
+    # http://www.cmake.org/Bug/print_bug_page.php?bug_id=11240
+    set(CMAKE_SHARED_LINKER_FLAGS "/machine:x64")
+  endif()
+
+  if(USE_IGN_RECOMMENDED_FLAGS)
+
+    # Gy: Prevent errors caused by multiply-defined symbols
+    # W2: Warning level 2: significant warnings.
+    #     TODO: Recommend Wall in the future.
+    #     Note: MSVC /Wall generates tons of warnings on gtest code.
+    set(MSVC_MINIMAL_FLAGS "/Gy /W2")
+
+    # Zi: Produce complete debug information
+    # Note: We provide Zi to ordinary release mode because it does not impact
+    # performance and can be helpful for debugging.
+    set(MSVC_DEBUG_FLAGS "${MSVC_MINIMAL_FLAGS} /Zi")
+
+    # GL: Enable Whole Program Optimization
+    set(MSVC_RELEASE_FLAGS "${MSVC_DEBUG_FLAGS} /GL")
+
+    # UNDEBUG: Undefine NDEBUG so that assertions can be triggered
+    set(MSVC_RELWITHDEBINFO_FLAGS "${MSVC_RELEASE_FLAGS} /UNDEBUG")
+
+    # cmake automatically provides /Zi /Ob0 /Od /RTC1
+    set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${IGN_RUNTIME_LIBRARY}d ${MSVC_DEBUG_FLAGS}")
+    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${IGN_RUNTIME_LIBRARY}d ${MSVC_DEBUG_FLAGS}")
+
+    # cmake automatically provides /O2 /Ob2 /DNDEBUG
+    set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${IGN_RUNTIME_LIBRARY} ${MSVC_RELEASE_FLAGS}")
+    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${IGN_RUNTIME_LIBRARY} ${MSVC_RELEASE_FLAGS}")
+
+    # cmake automatically provides /Zi /O2 /Ob1 /DNDEBUG
+    set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${IGN_RUNTIME_LIBRARY}d ${MSVC_RELWITHDEBINFO_FLAGS}")
+    set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${IGN_RUNTIME_LIBRARY}d ${MSVC_RELWITHDEBINFO_FLAGS}")
+
+    # cmake automatically provides /O1 /Ob1 /DNDEBUG
+    set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} ${IGN_RUNTIME_LIBRARY} ${MSVC_MINIMAL_FLAGS}")
+    set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${IGN_RUNTIME_LIBRARY} ${MSVC_MINIMAL_FLAGS}")
+
+    # NOTE: Leave CMAKE_C_FLAGS and CMAKE_CXX_FLAGS blank, because
+    # those will be appended to all build configurations.
+
+    # TODO: What flags should be set for PROFILE and COVERAGE build types?
+    #       Is it even possible to generate those build types on Windows?
+
+  endif()
+
+  # We always want this flag to be specified so we get standard-compliant
+  # exception handling.
+  # EHsc: Use standard-compliant exception handling
+  add_compile_options("/EHsc")
+
+endmacro()
diff --git a/cmake/IgnUtils.cmake b/cmake/IgnUtils.cmake
new file mode 100644
index 0000000..0a2e408
--- /dev/null
+++ b/cmake/IgnUtils.cmake
@@ -0,0 +1,906 @@
+
+#################################################
+# ign_find_package(<PACKAGE_NAME>
+#                  [REQUIRED] [EXACT] [QUIET] [PRIVATE] [BUILD_ONLY] [PKGCONFIG_IGNORE]
+#                  [VERSION <ver>]
+#                  [EXTRA_ARGS <args>]
+#                  [PRETTY <name>]
+#                  [PURPOSE <"explanation for this dependency">]
+#                  [PKGCONFIG <pkgconfig_name>]
+#                  [PKGCONFIG_LIB <lib_name>]
+#                  [PKGCONFIG_VER_COMPARISON <|>|=|<=|>=])
+#
+# This is a wrapper for the standard cmake find_package which behaves according
+# to the conventions of the ignition library. In particular, we do not quit
+# immediately when a required package is missing. Instead, we check all
+# dependencies and provide an overview of what is missing at the end of the
+# configuration process. Descriptions of the function arguments are as follows:
+#
+# <PACKAGE_NAME>: The name of the package as it would normally be passed to
+#                 find_package(~). Note if your package corresponds to a
+#                 find-module named FindABC.cmake, then <PACKAGE_NAME> must be
+#                 ABC, with the case matching. If the find-module is named
+#                 FindAbc.cmake, then <PACKAGE_NAME> must be Abc. This will not
+#                 necessarily match the library's actual name, nor will it
+#                 necessarily match the name used by pkgconfig, so there are
+#                 additional arguments (i.e. PRETTY, PKGCONFIG) to specify
+#                 alternative names for this package that can be used depending
+#                 on the context.
+#
+# [REQUIRED]: Optional. If provided, macro will trigger an ignition build_error
+#             when the package cannot be found. If not provided, this macro will
+#             trigger an ignition build_warning when the package is not found.
+#
+# [EXACT]: Optional. This will pass on the EXACT option to find_package(~) and
+#          also add it to the call to find_dependency(~) in the
+#          <project>-config.cmake file.
+#
+# [QUIET]: Optional. If provided, it will be passed forward to cmake's
+#          find_package(~) command. This macro will still print its normal
+#          output.
+#
+# [PRIVATE]: Optional. Use this to indicate that consumers of the project do not
+#            need to link against the package, but it must be present on the
+#            system, because our project must link against it.
+#
+# [BUILD_ONLY]: Optional. Use this to indicate that the project only needs this
+#               package while building, and it does not need to be available to
+#               the consumer of this project at all. Normally this should only
+#               apply to (1) a header-only library whose headers are included
+#               exclusively in the source files and not included in any public
+#               (i.e. installed) project headers, or to (2) a static library
+#               dependency.
+#
+# [PKGCONFIG_IGNORE]: Discouraged. If this option is provided, this package will
+#                     not be added to the project's pkgconfig file in any way.
+#                     This should only be used in very rare circumstances. Note
+#                     that BUILD_ONLY will also prevent a pkgconfig entry from
+#                     being produced.
+#
+# [VERSION]: Optional. Follow this argument with the major[.minor[.patch[.tweak]]]
+#            version that you need for this package.
+#
+# [EXTRA_ARGS]: Optional. Additional args to pass forward to find_package(~)
+#
+# [PRETTY]: Optional. If provided, the string that follows will replace
+#           <PACKAGE_NAME> when printing messages, warnings, or errors to the
+#           terminal.
+#
+# [PURPOSE]: Optional. If provided, the string that follows will be appended to
+#            the build_warning or build_error that this function produces when
+#            the package could not be found.
+#
+#  ==========================================================================
+#  The following arguments pertain to the automatic generation of your
+#  project's pkgconfig file. Ideally, this information should be provided
+#  automatically by ignition-cmake through the cmake find-module that is written
+#  for your dependency. However, if your package gets distributed with its own
+#  cmake config-file or find-module, then it might not automatically set this
+#  information. Therefore, we provide the ability to set it through your call to
+#  ign_find_package(~). Do not hesitate to ask for help if you need to use these
+#  arguments.
+#
+# [PKGCONFIG]: Optional. If provided, the string that follows will be used to
+#              specify a "required" package for pkgconfig. If not provided, then
+#              <PACKAGE_NAME> will be used instead.
+#
+# [PKGCONFIG_LIB]: Optional. Use this to indicate that the package should be
+#                  considered a "library" by pkgconfig. This is used for
+#                  libraries which do not come with *.pc metadata, such as
+#                  system libraries, libm, libdl, or librt. Generally you should
+#                  leave this out, because most packages will be considered
+#                  "modules" by pkgconfig. The string which follows this argument
+#                  will be used as the library name, and the string that follows
+#                  a PKGCONFIG argument will be ignored, so the PKGCONFIG
+#                  argument can be left out when using this argument.
+#
+# [PKGCONFIG_VER_COMPARISON]: Optional. If provided, pkgconfig will be told how
+#                             the available version of this package must compare
+#                             to the specified version. Acceptable values are
+#                             =, <, >, <=, >=. Default will be =. If no version
+#                             is provided using VERSION, then this will be left
+#                             out, whether or not it is provided.
+#
+macro(ign_find_package PACKAGE_NAME)
+
+  #------------------------------------
+  # Define the expected arguments
+  set(options REQUIRED EXACT QUIET PRIVATE BUILD_ONLY)
+  set(oneValueArgs VERSION PRETTY PURPOSE EXTRA_ARGS PKGCONFIG PKGCONFIG_LIB PKGCONFIG_VER_COMPARISON)
+  set(multiValueArgs) # We are not using multiValueArgs yet
+
+  #------------------------------------
+  # Parse the arguments
+  cmake_parse_arguments(ign_find_package "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+  #------------------------------------
+  # Construct the arguments to pass to find_package
+  if(ign_find_package_VERSION)
+    list(APPEND ${PACKAGE_NAME}_find_package_args ${ign_find_package_VERSION})
+  endif()
+
+  if(ign_find_package_QUIET)
+    list(APPEND ${PACKAGE_NAME}_find_package_args QUIET)
+  endif()
+
+  if(ign_find_package_EXACT)
+    list(APPEND ${PACKAGE_NAME}_find_package_args EXACT)
+  endif()
+
+  if(ign_find_package_EXTRA_ARGS)
+    list(APPEND ${PACKAGE_NAME}_find_package_args ${ign_find_package_EXTRA_ARGS})
+  endif()
+
+  #------------------------------------
+  # Figure out which name to print
+  if(ign_find_package_PRETTY)
+    set(${PACKAGE_NAME}_pretty ${ign_find_package_PRETTY})
+  else()
+    set(${PACKAGE_NAME}_pretty ${PACKAGE_NAME})
+  endif()
+
+
+  #------------------------------------
+  # Call find_package with the provided arguments
+  find_package(${PACKAGE_NAME} ${${PACKAGE_NAME}_find_package_args})
+  if(${PACKAGE_NAME}_FOUND)
+
+    message(STATUS "Looking for ${${PACKAGE_NAME}_pretty} - found\n")
+
+  else()
+
+    message(STATUS "Looking for ${${PACKAGE_NAME}_pretty} - not found\n")
+
+    #------------------------------------
+    # Construct the warning/error message to produce
+    set(${PACKAGE_NAME}_msg "Missing: ${${PACKAGE_NAME}_pretty}")
+    if(DEFINED ign_find_package_PURPOSE)
+      set(${PACKAGE_NAME}_msg "${${PACKAGE_NAME}_msg} - ${ign_find_package_PURPOSE}")
+    endif()
+
+    #------------------------------------
+    # Produce an error if the package is required, or a warning if it is not
+    if(ign_find_package_REQUIRED)
+      ign_build_error(${${PACKAGE_NAME}_msg})
+    else()
+      ign_build_warning(${${PACKAGE_NAME}_msg})
+    endif()
+  endif()
+
+
+  #------------------------------------
+  # Add this package to the list of dependencies that will be inserted into the
+  # find-config file, unless the invoker specifies that it should not be added.
+  # Also, add this package or library as an entry to the pkgconfig file that we
+  # will produce for our project.
+  if(ign_find_package_REQUIRED AND NOT ign_find_package_BUILD_ONLY)
+
+    # Set up the arguments we want to pass to the find_dependency invokation for
+    # our ignition project. We always need to pass the name of the dependency.
+    set(${PACKAGE_NAME}_dependency_args ${PACKAGE_NAME})
+
+    # If a version is provided here, we should pass that as well.
+    if(ign_find_package_VERSION)
+      ign_string_append(${PACKAGE_NAME}_dependency_args ${ign_find_package_VERSION})
+    endif()
+
+    # If we have specified the exact version, we should provide that as well.
+    if(ign_find_package_EXACT)
+      ign_string_append(${PACKAGE_NAME}_dependency_args EXACT)
+    endif()
+
+    ign_string_append(PROJECT_CMAKE_DEPENDENCIES "find_dependency(${${PACKAGE_NAME}_dependency_args})" DELIM "\n")
+
+    #------------------------------------
+    # Add this library or project to its relevant pkgconfig entry, unless we
+    # have been explicitly instructed to ignore it.
+    if(NOT ign_find_package_PKGCONFIG_IGNORE)
+
+      # Here we will set up the pkgconfig entry for this package. Ordinarily,
+      # these variables should be set by ign_pkg_check_modules[_quiet]. However,
+      # that might not be available for third-party dependencies that provide
+      # their own find-module or cmake config-module. Therefore, we provide the
+      # option of specifying pkgconfig information through the call to
+      # ign_find_package.
+
+      # If the caller has specified the arguments PKGCONFIG_LIB or PKGCONFIG,
+      # then we will overwrite these pkgconfig variables with the information
+      # provided by the caller.
+      if(ign_find_package_PKGCONFIG_LIB)
+        # Libraries must be prepended with -l
+        set(${PACKAGE_NAME}_PKGCONFIG_ENTRY "-l${ign_find_package_PKGCONFIG_LIB}")
+        set(${PACKAGE_NAME}_PKGCONFIG_TYPE PROJECT_PKGCONFIG_LIBS)
+      elseif(ign_find_package_PKGCONFIG)
+        # Modules (a.k.a. packages) can just be provided with the name
+        set(${PACKAGE_NAME}_PKGCONFIG_ENTRY "${ign_find_package_PKGCONFIG}")
+        set(${PACKAGE_NAME}_PKGCONFIG_TYPE PROJECT_PKGCONFIG_REQUIRES)
+
+        # Add the version requirements to the entry.
+        if(ign_find_package_VERSION)
+          # Use equivalency by default
+          set(comparison "=")
+
+          # If the caller has specified a version comparison operator, use that
+          # instead of equivalency.
+          if(ign_find_package_PKGCONFIG_VER_COMPARISON)
+            set(comparison ${ign_find_package_PKGCONFIG_VER_COMPARISON})
+          endif()
+
+          # Append the comparison and the version onto the pkgconfig entry
+          set(${PACKAGE_NAME}_PKGCONFIG_ENTRY "${${PACKAGE_NAME}_PKGCONFIG_ENTRY} ${comparison} ${ign_find_package_VERSION}")
+
+        endif()
+
+      endif()
+
+      if(ign_find_package_PRIVATE)
+        # If this is a private library or module, add the _PRIVATE suffix
+        set(${PACKAGE_NAME}_PKGCONFIG_TYPE ${${PACKAGE_NAME}_PKGCONFIG_TYPE}_PRIVATE)
+      endif()
+
+      # Append the entry as a string onto whichever type we selected
+      set(${${PACKAGE_NAME}_PKGCONFIG_TYPE} "${${${PACKAGE_NAME}_PKGCONFIG_TYPE}} ${${PACKAGE_NAME}_PKGCONFIG_ENTRY}")
+
+    endif()
+  endif()
+
+endmacro()
+
+#################################################
+# Macro to turn a list into a string (why doesn't CMake have this built-in?)
+macro(ign_list_to_string _string _list)
+    set(${_string})
+    foreach(_item ${_list})
+      set(${_string} "${${_string}} ${_item}")
+    endforeach(_item)
+    #string(STRIP ${${_string}} ${_string})
+endmacro()
+
+#################################################
+# ign_string_append(<output_var> <value_to_append> [DELIM <delimiter>])
+#
+# <output_var>: The name of the string variable that should be appended to
+#
+# <value_to_append>: The value that should be appended to the string
+#
+# [DELIM]: Specify a delimiter to separate the contents with. Default value is a
+#          space
+#
+# Macro to append a value to a string
+macro(ign_string_append output_var val)
+
+  #------------------------------------
+  # Define the expected arguments
+  set(options) # We are not using options yet
+  set(oneValueArgs DELIM)
+  set(multiValueArgs) # We are not using multiValueArgs yet
+
+  #------------------------------------
+  # Parse the arguments
+  cmake_parse_arguments(ign_string_append "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+  if(ign_string_append_DELIM)
+    set(delim "${ign_string_append_DELIM}")
+  else()
+    set(delim " ")
+  endif()
+
+  set(${output_var} "${${output_var}}${delim}${val}")
+
+endmacro()
+
+#################################################
+# ign_get_sources_and_unittests(<lib_srcs> <tests>)
+#
+# From the current directory, grab all the files ending in "*.cc" and sort them
+# into library source files <lib_srcs> and unittest source files <tests>. Remove
+# their paths to make them suitable for passing into ign_add_[library/tests].
+function(ign_get_libsources_and_unittests lib_sources_var tests_var)
+
+  # GLOB all the source files
+  file(GLOB source_files "*.cc")
+  list(SORT source_files)
+
+  # GLOB all the unit tests
+  file(GLOB test_files "*_TEST.cc")
+  list(SORT test_files)
+
+  # Initialize these lists
+  set(tests)
+  set(sources)
+
+  # Remove the unit tests from the list of source files
+  foreach(test_file ${test_files})
+
+    list(REMOVE_ITEM source_files ${test_file})
+
+    # Remove the path from the unit test and append to the list of tests.
+    get_filename_component(test ${test_file} NAME)
+    list(APPEND tests ${test})
+
+  endforeach()
+
+  foreach(source_file ${source_files})
+
+    # Remove the path from the library source file and append it to the list of
+    # library source files.
+    get_filename_component(source ${source_file} NAME)
+    list(APPEND sources ${source})
+
+  endforeach()
+
+  # Return the lists that have been created.
+  set(${lib_sources_var} ${sources} PARENT_SCOPE)
+  set(${tests_var} ${tests} PARENT_SCOPE)
+
+endfunction()
+
+#################################################
+# ign_get_sources(<sources>)
+#
+# From the current directory, grab all the source files and place them into
+# <sources>. Remove their paths to make them suitable for passing into
+# ign_add_[library/tests].
+function(ign_get_sources sources_var)
+
+  # GLOB all the source files
+  file(GLOB source_files "*.cc")
+  list(SORT source_files)
+
+  # Initialize this list
+  set(sources)
+
+  foreach(source_file ${source_files})
+
+    # Remove the path from the source file and append it the list of soures
+    get_filename_component(source ${source_file} NAME)
+    list(APPEND sources ${source})
+
+  endforeach()
+
+  # Return the list that has been created
+  set(${sources_var} ${sources} PARENT_SCOPE)
+
+endfunction()
+
+#################################################
+# ign_install_all_headers(
+#   [ADDITIONAL_DIRS <dirs>]
+#   [EXCLUDE <excluded_headers>]
+#   [GENERATED_HEADERS <headers>])
+#
+# From the current directory, install all header files, including files from the
+# "detail" subdirectory. You can optionally specify additional directories
+# (besides detail) to also install. You may also specify header files to
+# exclude from the installation. This will accept all files ending in *.h and
+# *.hh. You may append an additional suffix (like .old or .backup) to prevent
+# a file from being included here.
+#
+# GENERATED_HEADERS should be generated headers which should be included by
+# ${IGN_DESIGNATION}.hh. This will only add them to the header, it will not
+# generate or install them.
+#
+# This will also run configure_file on ign_auto_headers.hh.in and config.hh.in
+# and install both of them.
+function(ign_install_all_headers)
+
+  #------------------------------------
+  # Define the expected arguments
+  set(options) # We are not using options yet
+  set(oneValueArgs) # We are not using oneValueArgs yet
+  set(multiValueArgs ADDITIONAL_DIRS EXCLUDE GENERATED_HEADERS)
+
+  #------------------------------------
+  # Parse the arguments
+  cmake_parse_arguments(ign_install_all_headers "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+  #------------------------------------
+  # Build list of directories
+  set(dir_list "." "detail" ${ign_install_all_headers_ADDITIONAL_DIRS})
+
+  #------------------------------------
+  # Grab the excluded files
+  set(excluded ${ign_install_all_headers_EXCLUDE})
+
+  #------------------------------------
+  # Initialize the string of all headers
+  set(ign_headers)
+
+  #------------------------------------
+  # Install all the non-excluded headers
+  foreach(dir ${dir_list})
+
+    # GLOB all the header files in dir
+    file(GLOB header_files "${dir}/*.h" "${dir}/*.hh")
+    list(SORT header_files)
+
+    # Replace full paths with relative paths
+    set(headers)
+    foreach(header_file ${header_files})
+
+      get_filename_component(header ${header_file} NAME)
+      if("." STREQUAL ${dir})
+        list(APPEND headers ${header})
+      else()
+        list(APPEND headers ${dir}/${header})
+      endif()
+
+    endforeach()
+
+    # Remove the excluded headers
+    if(headers)
+      foreach(exclude ${excluded})
+        list(REMOVE_ITEM headers ${exclude})
+      endforeach()
+    endif()
+
+    # Add each header, prefixed by its directory, to the auto headers variable
+    foreach(header ${headers})
+      set(ign_headers "${ign_headers}#include <ignition/${IGN_DESIGNATION}/${header}>\n")
+    endforeach()
+
+    if("." STREQUAL ${dir})
+      set(destination "${IGN_INCLUDE_INSTALL_DIR_FULL}/ignition/${IGN_DESIGNATION}")
+    else()
+      set(destination "${IGN_INCLUDE_INSTALL_DIR_FULL}/ignition/${IGN_DESIGNATION}/${dir}")
+    endif()
+
+    install(
+      FILES ${headers}
+      DESTINATION ${destination}
+      COMPONENT headers)
+
+  endforeach()
+
+  # Add generated headers to the list of includes
+  foreach(header ${ign_install_all_headers_GENERATED_HEADERS})
+      set(ign_headers "${ign_headers}#include <ignition/${IGN_DESIGNATION}/${header}>\n")
+  endforeach()
+
+  # Define the install directory for the meta headers
+  set(meta_header_install_dir ${IGN_INCLUDE_INSTALL_DIR_FULL}/ignition/${IGN_DESIGNATION})
+
+  # Define the input/output of the configuration for the "master" header
+  set(master_header_in ${IGNITION_CMAKE_DIR}/ign_auto_headers.hh.in)
+  set(master_header_out ${CMAKE_CURRENT_BINARY_DIR}/${IGN_DESIGNATION}.hh)
+
+  # Generate the "master" header that includes all of the headers
+  configure_file(${master_header_in} ${master_header_out})
+
+  # Install the "master" header
+  install(
+    FILES ${master_header_out}
+    DESTINATION ${meta_header_install_dir}/..
+    COMPONENT headers)
+
+  # Define the input/output of the configuration for the "config" header
+  set(config_header_in ${CMAKE_CURRENT_SOURCE_DIR}/config.hh.in)
+  set(config_header_out ${CMAKE_CURRENT_BINARY_DIR}/config.hh)
+
+  if(NOT EXISTS ${config_header_in})
+    message(FATAL_ERROR
+      "Developer error: You are missing the file [${config_header_in}]! "
+      "Did you forget to move it from your project's cmake directory while "
+      "migrating to the use of ignition-cmake?")
+  endif()
+
+  # Generate the "config" header that describes our project configuration
+  configure_file(${config_header_in} ${config_header_out})
+
+  # Install the "config" header
+  install(
+    FILES ${config_header_out}
+    DESTINATION ${meta_header_install_dir}
+    COMPONENT headers)
+
+endfunction()
+
+
+#################################################
+# ign_build_error macro
+macro(ign_build_error)
+  foreach(str ${ARGN})
+    set(msg "\t${str}")
+    list(APPEND build_errors ${msg})
+  endforeach()
+endmacro(ign_build_error)
+
+#################################################
+# ign_build_warning macro
+macro(ign_build_warning)
+  foreach(str ${ARGN})
+    set(msg "\t${str}" )
+    list(APPEND build_warnings ${msg})
+  endforeach(str ${ARGN})
+endmacro(ign_build_warning)
+
+#################################################
+macro(ign_add_library lib_name)
+
+  set(LIBS_DESTINATION ${PROJECT_BINARY_DIR}/src)
+  add_library(${lib_name} ${ARGN})
+
+  if(IGN_ADD_fPIC_TO_LIBRARIES)
+    target_compile_options(${lib_name} PRIVATE -fPIC)
+  endif()
+
+  # This generator expression is necessary for multi-configuration generators,
+  # such as MSVC on Windows, and also to ensure that our target exports the
+  # headers correctly
+  target_include_directories(${lib_name}
+    PUBLIC
+      # This is the publicly installed ignition/math headers directory.
+      $<INSTALL_INTERFACE:${IGN_INCLUDE_INSTALL_DIR_FULL}>
+      # This is the build directory version of the headers. When exporting the
+      # target, this will not be included, because it is tied to the build
+      # interface instead of the install interface.
+      $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
+
+  set(binary_include_dir
+    "${CMAKE_BINARY_DIR}/include/ignition/${IGN_DESIGNATION_LOWER}")
+
+  set(implementation_file_name "${binary_include_dir}/detail/Export.hh")
+
+  include(GenerateExportHeader)
+  # This macro will generate a header called detail/Export.hh which implements
+  # some C-macros that are useful for exporting our libraries. The
+  # implementation header does not provide any commentary or explanation for its
+  # macros, so we tuck it away in the detail/ subdirectory, and then provide a
+  # public-facing header that provides commentary for the macros.
+  generate_export_header(${lib_name}
+    BASE_NAME ${PROJECT_NAME_NO_VERSION_UPPER}
+    EXPORT_FILE_NAME ${implementation_file_name}
+    EXPORT_MACRO_NAME DETAIL_IGNITION_${IGN_DESIGNATION_UPPER}_VISIBLE
+    NO_EXPORT_MACRO_NAME DETAIL_IGNITION_${IGN_DESIGNATION_UPPER}_HIDDEN
+    DEPRECATED_MACRO_NAME IGN_DEPRECATED_ALL_VERSIONS)
+
+  set(install_include_dir
+    "${IGN_INCLUDE_INSTALL_DIR_FULL}/ignition/${IGN_DESIGNATION}")
+
+  # Configure the installation of the automatically generated file.
+  install(
+    FILES "${implementation_file_name}"
+    DESTINATION "${install_include_dir}/detail"
+    COMPONENT headers)
+
+  # Configure the public-facing header for exporting and deprecating. This
+  # header provides commentary for the macros so that developers can know their
+  # purpose.
+  configure_file(
+    "${IGNITION_CMAKE_DIR}/Export.hh.in"
+    "${binary_include_dir}/Export.hh")
+
+  # Configure the installation of the public-facing header.
+  install(
+    FILES "${binary_include_dir}/Export.hh"
+    DESTINATION "${install_include_dir}"
+    COMPONENT headers)
+
+endmacro()
+
+#################################################
+macro(ign_add_static_library _name)
+  add_library(${_name} STATIC ${ARGN})
+  target_link_libraries(${_name} ${general_libraries})
+endmacro()
+
+#################################################
+macro(ign_add_executable _name)
+  add_executable(${_name} ${ARGN})
+  target_link_libraries(${_name} ${general_libraries})
+endmacro()
+
+#################################################
+# ign_target_interface_include_directories(<target> [include_targets])
+#
+# Add the INTERFACE_INCLUDE_DIRECTORIES of [include_targets] to the public
+# INCLUDE_DIRECTORIES of <target>. This allows us to propagate the include
+# directories of <target> along to any other libraries that depend on it.
+#
+# You MUST pass in targets to include, not directory names. We must not use
+# explicit directory names here if we want our package to be relocatable.
+function(ign_target_interface_include_directories name)
+
+  foreach(include_target ${ARGN})
+    target_include_directories(
+      ${name} PUBLIC
+      $<TARGET_PROPERTY:${include_target},INTERFACE_INCLUDE_DIRECTORIES>)
+  endforeach()
+
+endfunction()
+
+#################################################
+macro(ign_install_includes _subdir)
+  install(FILES ${ARGN}
+    DESTINATION ${IGN_INCLUDE_INSTALL_DIR}/${_subdir} COMPONENT headers)
+endmacro()
+
+#################################################
+macro(ign_install_library)
+
+  if(${ARGC} GREATER 0)
+    message(WARNING "Warning to the developer: ign_install_library no longer "
+                    "accepts any arguments. Please remove them from your call.")
+  endif()
+
+  set_target_properties(
+    ${PROJECT_LIBRARY_TARGET_NAME}
+    PROPERTIES
+      SOVERSION ${PROJECT_VERSION_MAJOR}
+      VERSION ${PROJECT_VERSION_FULL})
+
+  install(
+    TARGETS ${PROJECT_LIBRARY_TARGET_NAME}
+    EXPORT ${PROJECT_EXPORT_NAME}
+    LIBRARY DESTINATION ${IGN_LIB_INSTALL_DIR}
+    ARCHIVE DESTINATION ${IGN_LIB_INSTALL_DIR}
+    RUNTIME DESTINATION ${IGN_LIB_INSTALL_DIR}
+    COMPONENT shlib)
+
+endmacro()
+
+#################################################
+macro(ign_install_executable _name )
+  set_target_properties(${_name} PROPERTIES VERSION ${PROJECT_VERSION_FULL})
+  install (TARGETS ${_name} DESTINATION ${IGN_BIN_INSTALL_DIR})
+  manpage(${_name} 1)
+endmacro()
+
+#################################################
+# Macro to setup supported compiler warnings
+# Based on work of Florent Lamiraux, Thomas Moulard, JRL, CNRS/AIST.
+macro(ign_filter_valid_compiler_options var)
+
+  include(CheckCXXCompilerFlag)
+  # Store the current setting for CMAKE_REQUIRED_QUIET
+  set(original_cmake_required_quiet ${CMAKE_REQUIRED_QUIET})
+
+  # Make these tests quiet so they don't pollute the cmake output
+  set(CMAKE_REQUIRED_QUIET true)
+
+  foreach(flag ${ARGN})
+    CHECK_CXX_COMPILER_FLAG(${flag} result${flag})
+    if(result${flag})
+      set(${var} "${${var}} ${flag}")
+    endif()
+  endforeach()
+
+  # Restore the old setting for CMAKE_REQUIRED_QUIET
+  set(CMAKE_REQUIRED_QUIET ${original_cmake_required_quiet})
+endmacro()
+
+#################################################
+# ign_build_executables(SOURCES <sources>
+#                       [PREFIX <prefix>]
+#                       [LIB_DEPS <library_dependencies>]
+#                       [INCLUDE_DIRS <include_dependencies>]
+#                       [EXEC_LIST <output_var>]
+#                       [EXCLUDE_PROJECT_LIB])
+#
+# Build executables for an ignition project. Arguments are as follows:
+#
+# SOURCES: Required. The names (without a path) of the source files for your
+#          executables.
+#
+# PREFIX: Optional. This will append <prefix> onto each executable name.
+#
+# LIB_DEPS: Optional. Additional library dependencies that every executable
+#           should link to, not including the library build by this project (it
+#           will be linked automatically, unless you pass in the
+#           EXCLUDE_PROJECT_LIB option).
+#
+# INCLUDE_DIRS: Optional. Additional include directories that should be visible
+#               to all of these executables.
+#
+# EXEC_LIST: Optional. Provide a variable which will be given the list of the
+#            names of the executables generated by this macro. These will also
+#            be the names of the targets.
+#
+# EXCLUDE_PROJECT_LIB: Pass this argument if you do not want your executables to
+#                      link to your project's main library. On Windows, this
+#                      will also skip the step of copying the runtime library
+#                      into your executable's directory.
+#
+macro(ign_build_executables)
+
+  #------------------------------------
+  # Define the expected arguments
+  set(options EXCLUDE_PROJECT_LIB)
+  set(oneValueArgs PREFIX EXEC_LIST)
+  set(multiValueArgs SOURCES LIB_DEPS INCLUDE_DIRS)
+
+  if(ign_build_executables_EXEC_LIST)
+    set(${ign_build_executables_EXEC_LIST} "")
+  endif()
+
+
+  #------------------------------------
+  # Parse the arguments
+  cmake_parse_arguments(ign_build_executables "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+  foreach(exec_file ${ign_build_executables_SOURCES})
+
+    string(REGEX REPLACE ".cc" "" BINARY_NAME ${exec_file})
+    set(BINARY_NAME ${ign_build_executables_PREFIX}${BINARY_NAME})
+
+    add_executable(${BINARY_NAME} ${exec_file})
+
+    if(ign_build_executables_EXEC_LIST)
+      list(APPEND ${ign_build_executables_EXEC_LIST} ${BINARY_NAME})
+    endif()
+
+    if(NOT ign_build_executables_EXCLUDE_PROJECT_LIB)
+      target_link_libraries(${BINARY_NAME} ${PROJECT_LIBRARY_TARGET_NAME})
+    endif()
+
+    if(ign_build_executables_LIB_DEPS)
+      target_link_libraries(${BINARY_NAME} ${ign_build_executables_LIB_DEPS})
+    endif()
+
+    target_include_directories(${BINARY_NAME}
+      PRIVATE
+        ${PROJECT_SOURCE_DIR}
+        ${PROJECT_SOURCE_DIR}/include
+        ${PROJECT_BINARY_DIR}
+        ${PROJECT_BINARY_DIR}/include
+        ${ign_build_executables_INCLUDE_DIRS})
+
+      if(WIN32 AND NOT ign_build_executables_EXCLUDE_PROJECT_LIB)
+
+        # If we have not installed our project's library yet, then it will not
+        # be visible to the executable when we attempt to run it. Therefore, we
+        # place a copy of our project's library into the directory that contains
+        # the executable. We do not need to do this for any of the test's other
+        # dependencies, because the fact that they were found by the build
+        # system means they are installed and should be visible when the test is
+        # run.
+
+        # Get the full file path to the original dll for this project
+        set(dll_original "$<TARGET_FILE:${PROJECT_LIBRARY_TARGET_NAME}>")
+
+        # Get the full file path for where we need to paste the dll for this project
+        set(dll_target "$<TARGET_FILE_DIR:${BINARY_NAME}>/$<TARGET_FILE_NAME:${PROJECT_LIBRARY_TARGET_NAME}>")
+
+        # Add the copy_if_different command as a custom command that is tied the target
+        # of this test.
+        add_custom_command(
+          TARGET ${BINARY_NAME}
+          COMMAND ${CMAKE_COMMAND}
+          ARGS -E copy_if_different ${dll_original} ${dll_target}
+          VERBATIM)
+
+      endif()
+
+  endforeach()
+
+endmacro()
+
+#################################################
+# ign_build_tests(TYPE <test_type>
+#                 SOURCES <sources>
+#                 [LIB_DEPS <library_dependencies>]
+#                 [INCLUDE_DIRS <include_dependencies>]
+#                 [TEST_LIST <output_var>])
+#
+# Build tests for an ignition project. Arguments are as follows:
+#
+# TYPE: Required. Preferably UNIT, INTEGRATION, PERFORMANCE, or REGRESSION.
+#
+# SOURCES: Required. The names (without the path) of the source files for your
+#          tests. Each file will turn into a test.
+#
+# LIB_DEPS: Optional. Additional library dependencies that every test should
+#           link to, not including the library built by this project (it will be
+#           linked automatically). gtest and gtest_main will also be linked.
+#
+# INCLUDE_DIRS: Optional. Additional include directories that should be visible
+#               to all the tests of this type.
+#
+# TEST_LIST: Optional. Provide a variable which will be given the list of the
+#            names of the tests generated by this macro. These will also be the
+#            names of the targets.
+#
+macro(ign_build_tests)
+
+  #------------------------------------
+  # Define the expected arguments
+  set(options)
+  set(oneValueArgs TYPE)
+  set(multiValueArgs SOURCES LIB_DEPS INCLUDE_DIRS)
+
+  #------------------------------------
+  # Parse the arguments
+  cmake_parse_arguments(ign_build_tests "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+  if(NOT ign_build_tests_TYPE)
+    # If you have encountered this error, you are probably migrating to the
+    # new ignition-cmake system. Be sure to also provide a SOURCES argument
+    # when calling ign_build_tests.
+    message(FATAL_ERROR "Developer error: You must specify a TYPE for your tests!")
+  endif()
+
+  set(TEST_TYPE ${ign_build_tests_TYPE})
+
+  if(BUILD_TESTING)
+
+    if(NOT DEFINED ign_build_tests_SOURCES)
+      message(STATUS "No tests have been specified for ${TEST_TYPE}")
+    else()
+      list(LENGTH ign_build_tests_SOURCES num_tests)
+      message(STATUS "Adding ${num_tests} ${TEST_TYPE} tests")
+    endif()
+
+    ign_build_executables(
+      PREFIX "${TEST_TYPE}_"
+      SOURCES ${ign_build_tests_SOURCES}
+      LIB_DEPS gtest gtest_main ${ign_build_tests_LIB_DEPS}
+      INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/test/gtest/include ${ign_build_tests_INCLUDE_DIRS}
+      EXEC_LIST test_list)
+
+    if(ign_build_tests_TEST_LIST)
+      set(${ign_build_tests_TEST_LIST} ${test_list})
+    endif()
+
+    # Find the Python interpreter for running the
+    # check_test_ran.py script
+    find_package(PythonInterp QUIET)
+
+    # Build all the tests
+    foreach(BINARY_NAME ${test_list})
+
+      if(USE_LOW_MEMORY_TESTS)
+        target_compile_options(${BINARY_NAME} PRIVATE -DUSE_LOW_MEMORY_TESTS=1)
+      endif()
+
+      add_test(${BINARY_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}
+               --gtest_output=xml:${CMAKE_BINARY_DIR}/test_results/${BINARY_NAME}.xml)
+
+      if(UNIX)
+        # gtest requies pthread when compiled on a Unix machine
+        target_link_libraries(${BINARY_NAME} pthread)
+      endif()
+
+      set_tests_properties(${BINARY_NAME} PROPERTIES TIMEOUT 240)
+
+      if(PYTHONINTERP_FOUND)
+        # Check that the test produced a result and create a failure if it didn't.
+        # Guards against crashed and timed out tests.
+        add_test(check_${BINARY_NAME} ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/check_test_ran.py
+          ${CMAKE_BINARY_DIR}/test_results/${BINARY_NAME}.xml)
+      endif()
+    endforeach()
+
+  else()
+
+    message(STATUS "Testing is disabled -- skipping ${TEST_TYPE} tests")
+
+  endif()
+
+endmacro()
+
+#################################################
+# ign_set_target_public_cxx_standard(<11|14>)
+#
+# This lets you set the C++ standard required to compile and/or link against
+# your project's main library target. Acceptable options for the standard are 11
+# and 14.
+#
+# NOTE: This is a temporary workaround for the first pull request and will be
+#       removed in the very next revision of ignition-cmake.
+#
+macro(ign_set_project_public_cxx_standard standard)
+
+  list(FIND IGN_KNOWN_CXX_STANDARDS ${standard} known)
+  if(${known} EQUAL -1)
+    message(FATAL_ERROR "Specified invalid standard: ${standard}. Accepted values are: ${IGN_KNOWN_CXX_STANDARDS}.")
+  endif()
+
+  target_compile_features(${PROJECT_LIBRARY_TARGET_NAME} PUBLIC ${IGN_CXX_${standard}_FEATURES})
+
+  ign_string_append(PROJECT_PKGCONFIG_CFLAGS "-std=c++${standard}")
+  set(PROJECT_PKGCONFIG_CFLAGS ${PROJECT_PKGCONFIG_CFLAGS} PARENT_SCOPE)
+
+endmacro()
+
+
+
diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in
new file mode 100644
index 0000000..f767ae3
--- /dev/null
+++ b/cmake/cmake_uninstall.cmake.in
@@ -0,0 +1,21 @@
+if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+  message(FATAL_ERROR "Cannot find install manifest: '@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt'")
+endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+string(REGEX REPLACE "\n" ";" files "${files}")
+foreach(file ${files})
+  message(STATUS "Uninstalling '$ENV{DESTDIR}${file}'")
+  if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+    exec_program(
+      "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+      OUTPUT_VARIABLE rm_out
+      RETURN_VALUE rm_retval
+      )
+    if(NOT "${rm_retval}" STREQUAL 0)
+      message(FATAL_ERROR "Problem when removing '$ENV{DESTDIR}${file}'")
+    endif(NOT "${rm_retval}" STREQUAL 0)
+  else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+    message(STATUS "File '$ENV{DESTDIR}${file}' does not exist.")
+  endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+endforeach(file)
diff --git a/cmake/cpack_options.cmake.in b/cmake/cpack_options.cmake.in
new file mode 100644
index 0000000..22ba9de
--- /dev/null
+++ b/cmake/cpack_options.cmake.in
@@ -0,0 +1,28 @@
+set(CPACK_PACKAGE_NAME "@PROJECT_NAME_NO_VERSION@")
+set(CPACK_PACKAGE_VENDOR "osrfoundation.org")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY
+  "A set of @IGN_DESIGNATION@ classes for robot applications.")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "@PROJECT_NAME_NO_VERSION_LOWER@")
+set(CPACK_RESOURCE_FILE_LICENSE "@CMAKE_CURRENT_SOURCE_DIR@/LICENSE")
+set(CPACK_RESOURCE_FILE_README "@CMAKE_CURRENT_SOURCE_DIR@/README.md")
+set(CPACK_PACKAGE_DESCRIPTION_FILE "@CMAKE_CURRENT_SOURCE_DIR@/README.md")
+set(CPACK_PACKAGE_MAINTAINER "Nate Koenig <nate at osrfoundation.org>")
+set(CPACK_PACKAGE_CONTACT "Nate Koenig <natekoenig at osrfoundation.org>")
+
+set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "@DPKG_ARCH@")
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "@DEBIAN_PACKAGE_DEPENDS@")
+set(CPACK_DEBIAN_PACKAGE_SECTION "devel")
+set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+set(CPACK_DEBIAN_PACKAGE_DESCRIPTION
+  "A set of @IGN_DESIGNATION@ classes for robot applications.")
+
+set(CPACK_RPM_PACKAGE_ARCHITECTURE "@DPKG_ARCH@")
+set(CPACK_RPM_PACKAGE_REQUIRES "@DEBIAN_PACKAGE_DEPENDS@")
+set(CPACK_RPM_PACKAGE_DESCRIPTION
+  "A set of @IGN_DESIGNATION@ classes for robot applications.")
+
+set (CPACK_PACKAGE_FILE_NAME
+  "@PROJECT_NAME_NO_VERSION_LOWER at -@PROJECT_VERSION_FULL@")
+set (CPACK_SOURCE_PACKAGE_FILE_NAME
+  "@PROJECT_NAME_NO_VERSION_LOWER at -@PROJECT_VERSION_FULL@")
diff --git a/cmake/ign_auto_headers.hh.in b/cmake/ign_auto_headers.hh.in
new file mode 100644
index 0000000..42fc964
--- /dev/null
+++ b/cmake/ign_auto_headers.hh.in
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 Open Source Robotics Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+//                ****** Do not modify this file. ******
+// This file is automatically generated by CMake. Changes should instead be
+// made to cmake/ign_auto_headers.hh.in in ignition-cmake
+
+#include <ignition/@IGN_DESIGNATION@/config.hh>
+${ign_headers}
diff --git a/cmake/ignition-config.cmake.in b/cmake/ignition-config.cmake.in
new file mode 100644
index 0000000..d3f3b96
--- /dev/null
+++ b/cmake/ignition-config.cmake.in
@@ -0,0 +1,71 @@
+# - Config file for the @PKG_NAME@ package.
+#
+# For finding and loading @PKG_NAME@ from your project, type:
+#
+# find_package(@PKG_NAME@)
+#
+# It defines the following variables:
+#
+#  @PKG_NAME at _FOUND        - System has @PKG_NAME at .
+#  @PKG_NAME at _INCLUDE_DIRS - include directories for @PKG_NAME@ and its dependencies.
+#  @PKG_NAME at _LIBRARY_DIRS - Paths in which the linker should search for libraries.
+#  @PKG_NAME at _LIBRARIES    - Libraries to link against.
+#  @PKG_NAME at _LDFLAGS      - Linker flags.
+#
+# Additionally, it will create an imported target named @PROJECT_EXPORT_NAME@::@PROJECT_EXPORT_NAME at .
+# You can link your library against that target using target_link_library(~),
+# and all the variables mentioned above will automatically be pulled into your
+# target.
+
+# We explicitly set the desired cmake version to ensure that the policy settings
+# of users or of toolchains do not result in the wrong behavior for our modules.
+# Note that the call to find_package(~) will PUSH a new policy stack before
+# taking on these version settings, and then that stack will POP after the
+# find_package(~) has exited, so this will not affect the cmake policy settings
+# of a caller.
+cmake_minimum_required(VERSION 3.5.1 FATAL_ERROR)
+
+
+if(@PKG_NAME at _CONFIG_INCLUDED)
+  return()
+endif()
+set(@PKG_NAME at _CONFIG_INCLUDED TRUE)
+
+ at PACKAGE_INIT@
+
+if(NOT TARGET @PROJECT_EXPORT_NAME@::@PROJECT_EXPORT_NAME@)
+  include("${CMAKE_CURRENT_LIST_DIR}/@ign_targets_output@")
+endif()
+
+# On windows we produce .dll libraries with no prefix
+if(WIN32)
+ set(CMAKE_FIND_LIBRARY_PREFIXES "")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".dll")
+endif()
+
+# Package variables. Note that @PKG_NAME at _LIBRARIES merely contains an imported
+# target for the library, so it is sufficient to simply link to
+# @PKG_NAME at _LIBRARIES. None of the other package variables are needed.
+set(@PKG_NAME at _LIBRARIES @PROJECT_EXPORT_NAME@::@PROJECT_EXPORT_NAME@)
+set(@PKG_NAME at _INCLUDE_DIRS "@PACKAGE_IGN_INCLUDE_INSTALL_DIR_FULL@")
+set(@PKG_NAME at _LIBRARY_DIRS "@PACKAGE_IGN_LIB_INSTALL_DIR@")
+set(@PKG_NAME at _LDFLAGS      "-L at PACKAGE_IGN_LIB_INSTALL_DIR@")
+
+# Backwards compatibility variables
+set(@PROJECT_NAME_NO_VERSION_UPPER at _LIBRARIES ${@PKG_NAME at _LIBRARIES})
+set(@PROJECT_NAME_NO_VERSION_UPPER at _INCLUDE_DIRS ${@PKG_NAME at _INCLUDE_DIRS})
+
+# These variables are used by ignition-cmake to automatically configure the
+# pkgconfig files for ignition projects.
+set(@PKG_NAME at _PKGCONFIG_ENTRY "@PKG_NAME@")
+set(@PKG_NAME at _PKGCONFIG_TYPE PROJECT_PKGCONFIG_REQUIRES)
+
+# Get access to the find_dependency utility
+include(CMakeFindDependencyMacro)
+
+# Find ignition-cmake, because we need its modules in order to find the rest of
+# our dependencies.
+find_dependency(ignition-cmake at IGNITION_CMAKE_VERSION_MAJOR@)
+
+# Find each dependency of this project (if nothing is below, then the project
+# has no external dependencies). at PROJECT_CMAKE_DEPENDENCIES@
diff --git a/cmake/pkgconfig/ignition.pc.in b/cmake/pkgconfig/ignition.pc.in
new file mode 100644
index 0000000..dae2e40
--- /dev/null
+++ b/cmake/pkgconfig/ignition.pc.in
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
+includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@/ignition/@IGN_DESIGNATION@@PROJECT_VERSION_MAJOR@
+
+Name: Ignition @IGN_DESIGNATION@
+Description: A set of @IGN_DESIGNATION@ classes for robot applications
+Version: @PROJECT_VERSION_FULL@
+Requires:@PROJECT_PKGCONFIG_REQUIRES@
+Requires.private:@PROJECT_PKGCONFIG_REQUIRES_PRIVATE@
+Libs: -L${libdir} -l at PROJECT_NAME_LOWER@ @PROJECT_PKGCONFIG_LIBS@
+Libs.private:@PROJECT_PKGCONFIG_LIBS_PRIVATE@
+CFlags: -I${includedir} @PROJECT_PKGCONFIG_CFLAGS@
diff --git a/cmake/upload_doc.sh.in b/cmake/upload_doc.sh.in
new file mode 100644
index 0000000..634f02f
--- /dev/null
+++ b/cmake/upload_doc.sh.in
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# Check if the node was configured to use s3cmd
+# This is done by running s3cmd --configure
+if [ ! -f "${HOME}/.s3cfg" ]; then
+    echo "No $HOME/.s3cfg file found. Please config the software first in your system"
+    exit 1
+fi
+
+# Make documentation if not build
+if [ ! -f "@CMAKE_BINARY_DIR@/doxygen/html/index.html" ]; then
+  make doc
+  if [ ! -f "@CMAKE_BINARY_DIR@/doxygen/html/index.html" ]; then
+    echo "Documentation not present. Install doxygen, and run `make doc` in the build directory"
+    exit 1
+  fi
+fi
+
+# Dry run
+s3cmd sync @CMAKE_BINARY_DIR@/doxygen/html/* s3://osrf-distributions/ign- at IGN_DESIGNATION@/api/@PROJECT_VERSION_FULL@/ --dry-run -v
+
+echo -n "Upload (Y/n)? "
+read ans
+
+if [ "$ans" = "n" ] || [ "$ans" = "N" ]; then
+  exit 1
+else
+  s3cmd sync @CMAKE_BINARY_DIR@/doxygen/html/* s3://osrf-distributions/ign- at IGN_DESIGNATION@/api/@PROJECT_VERSION_FULL@/ -v
+fi
diff --git a/config/ignition-cmake-config.cmake.in b/config/ignition-cmake-config.cmake.in
new file mode 100644
index 0000000..36d1f7c
--- /dev/null
+++ b/config/ignition-cmake-config.cmake.in
@@ -0,0 +1,35 @@
+# - Config file for ignition-cmake (not for any other ignition libraries).
+#
+# To find and load ignition-cmake modules into your project, simply invoke:
+#
+# find_package(@PKG_NAME@)
+#
+# That will define the variable @PKG_NAME at _FOUND, and will open up access
+# to all the cmake-modules and find-modules that are provided by ignition-cmake.
+
+# We explicitly set the desired cmake version to ensure that the policy settings
+# of users or of toolchains do not result in the wrong behavior for our modules.
+# Note that the call to find_package(~) will PUSH a new policy stack before
+# taking on these version settings, and then that stack will POP after the
+# find_package(~) has exited, so this will not affect the cmake policy settings
+# of a caller.
+cmake_minimum_required(VERSION 3.5.1 FATAL_ERROR)
+
+#--------------------------------------
+# Initialize the IGNITION_CMAKE_DIR variable with the location of the cmake
+# directory that sits next to this find-module.
+set(IGNITION_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake at PROJECT_VERSION_MAJOR@")
+
+#--------------------------------------
+# Add the location of this package's cmake directory to the CMAKE_MODULE_PATH
+list(APPEND CMAKE_MODULE_PATH "${IGNITION_CMAKE_DIR}")
+
+#--------------------------------------
+# include the master IgnCMake module
+include(IgnCMake)
+
+#--------------------------------------
+# Create a variable to indicate what version of ignition-cmake we are using.
+# This variable does not follow the usual cmake naming convention because it is
+# a non-standard package variable.
+set(IGNITION_CMAKE_VERSION_MAJOR @PROJECT_VERSION_MAJOR@)
diff --git a/configure.bat b/configure.bat
new file mode 100644
index 0000000..001625a
--- /dev/null
+++ b/configure.bat
@@ -0,0 +1,15 @@
+
+:: NOTE: This script is only meant to be used as part of the ignition developers' CI system
+:: Users and developers should build and install this library using cmake and Visual Studio
+
+:: ign-cmake has no dependencies
+
+:: Go to the directory that this file configure.bat file exists in
+cd /d %~dp0
+
+:: Create a build directory and configure
+md build
+cd build
+cmake .. -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX="%WORKSPACE_INSTALL_DIR%"
+
+:: If the caller wants to build and/or install, they should do so after calling this script
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 0000000..fe535a9
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1 @@
+# TODO: Write documentation for ignition-cmake
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 0000000..e88cd37
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,74 @@
+include(ExternalProject)
+
+# test multiple build types
+set(build_types Release RelWithDebInfo Debug)
+find_program(EXAMPLE_LCOV_PATH lcov)
+if (NOT WIN32 AND EXAMPLE_LCOV_PATH)
+  list(APPEND build_types Coverage)
+endif()
+
+set(example_directories ign_configure_build prerelease)
+
+foreach(example ${example_directories})
+  if (${example} STREQUAL "ign_configure_build")
+    set(example_tarball_name ignition-minimal-0.1.0.tar.bz2)
+  elseif (${example} STREQUAL "prerelease")
+    set(example_tarball_name ignition-minimal-0.1.0~pre1.tar.bz2)
+  endif()
+
+  foreach (build_type ${build_types})
+    set(EXAMPLE_NAME ${example}_${build_type})
+    string(TIMESTAMP EXAMPLE_TIME)
+    configure_file(
+      "${CMAKE_CURRENT_SOURCE_DIR}/junit_pass.xml.in"
+      "${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE_NAME}_pass.xml"
+      @ONLY)
+    configure_file(
+      "${CMAKE_CURRENT_SOURCE_DIR}/junit_fail.xml.in"
+      "${CMAKE_CURRENT_BINARY_DIR}/test_results/${EXAMPLE_NAME}.xml"
+      @ONLY)
+    ExternalProject_Add(
+      ${EXAMPLE_NAME}
+
+      SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${example}"
+      # BUILD_ALWAYS needed since cmake doesn't notice when
+      # example files change.
+      # See alternate approach in a2113e0997c9 if this becomes too slow
+      BUILD_ALWAYS 1
+      CMAKE_ARGS
+        "-DCMAKE_PREFIX_PATH=${CMAKE_BINARY_DIR}"
+        "-DCMAKE_BUILD_TYPE=${build_type}"
+      TEST_COMMAND
+        ${CMAKE_COMMAND} -E copy
+        "${CMAKE_CURRENT_BINARY_DIR}/${EXAMPLE_NAME}_pass.xml"
+        "${CMAKE_CURRENT_BINARY_DIR}/test_results/${EXAMPLE_NAME}.xml"
+    )
+    if (CPACK_GENERATOR)
+      ExternalProject_Add_Step(
+        ${EXAMPLE_NAME}
+        package_source
+        COMMAND
+          ${CMAKE_COMMAND} --build <BINARY_DIR> --target package_source
+        DEPENDEES
+          configure
+      )
+      ExternalProject_Add_Step(
+        ${EXAMPLE_NAME}
+        test_tarball_name
+        COMMAND
+          ${CMAKE_COMMAND} -E tar tf <BINARY_DIR>/${example_tarball_name}
+        DEPENDEES
+          package_source
+        DEPENDERS
+          test
+      )
+    endif()
+    add_test(
+      ${EXAMPLE_NAME}
+      ${CMAKE_COMMAND} -E copy
+      "${CMAKE_CURRENT_BINARY_DIR}/test_results/${EXAMPLE_NAME}.xml"
+      "${CMAKE_BINARY_DIR}/test_results/${EXAMPLE_NAME}.xml"
+    )
+  endforeach()
+
+endforeach()
diff --git a/examples/ign_configure_build/CMakeLists.txt b/examples/ign_configure_build/CMakeLists.txt
new file mode 100644
index 0000000..2c864f0
--- /dev/null
+++ b/examples/ign_configure_build/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.5.1 FATAL_ERROR)
+find_package(ignition-cmake0 REQUIRED)
+ign_configure_project(minimal 0.1.0)
+ign_configure_build(QUIT_IF_BUILD_ERRORS)
\ No newline at end of file
diff --git a/examples/ign_configure_build/README.md b/examples/ign_configure_build/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/examples/ign_configure_build/doc/CMakeLists.txt b/examples/ign_configure_build/doc/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
diff --git a/examples/ign_configure_build/include/CMakeLists.txt b/examples/ign_configure_build/include/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
diff --git a/examples/ign_configure_build/src/CMakeLists.txt b/examples/ign_configure_build/src/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
diff --git a/examples/ign_configure_build/test/CMakeLists.txt b/examples/ign_configure_build/test/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
diff --git a/examples/junit_fail.xml.in b/examples/junit_fail.xml.in
new file mode 100644
index 0000000..d3cd930
--- /dev/null
+++ b/examples/junit_fail.xml.in
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="1" failures="1" disabled="0" errors="0" timestamp="@EXAMPLE_TIME@" time="0" name="AllTests">
+  <testsuite name="@EXAMPLE_NAME@" tests="1" failures="1" disabled="0" errors="0" time="0">
+    <testcase name="make" status="run" time="0" classname="@EXAMPLE_NAME@">
+      <failure type="Standard" message="Example @EXAMPLE_NAME@ failed to build." />
+    </testcase>
+  </testsuite>
+</testsuites>
diff --git a/examples/junit_pass.xml.in b/examples/junit_pass.xml.in
new file mode 100644
index 0000000..77d541d
--- /dev/null
+++ b/examples/junit_pass.xml.in
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="1" failures="0" disabled="0" errors="0" timestamp="@EXAMPLE_TIME@" time="0" name="AllTests">
+  <testsuite name="@EXAMPLE_NAME@" tests="1" failures="0" disabled="0" errors="0" time="0">
+    <testcase name="make" status="run" time="0" classname="@EXAMPLE_NAME@" />
+  </testsuite>
+</testsuites>
diff --git a/examples/prerelease/CMakeLists.txt b/examples/prerelease/CMakeLists.txt
new file mode 100644
index 0000000..b5fd55b
--- /dev/null
+++ b/examples/prerelease/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.5.1 FATAL_ERROR)
+find_package(ignition-cmake0 REQUIRED)
+ign_configure_project(minimal 0.1.0 VERSION_SUFFIX pre1)
+ign_configure_build(QUIT_IF_BUILD_ERRORS)
diff --git a/examples/prerelease/README.md b/examples/prerelease/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/examples/prerelease/doc/CMakeLists.txt b/examples/prerelease/doc/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
diff --git a/examples/prerelease/include/CMakeLists.txt b/examples/prerelease/include/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
diff --git a/examples/prerelease/src/CMakeLists.txt b/examples/prerelease/src/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
diff --git a/examples/prerelease/test/CMakeLists.txt b/examples/prerelease/test/CMakeLists.txt
new file mode 100644
index 0000000..e69de29
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..9303a08
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,9 @@
+if (UNIX)
+  add_test(cmake_minimum_required_match
+    bash
+    ${CMAKE_CURRENT_SOURCE_DIR}/cmake_minimum_required.bash
+    ${CMAKE_SOURCE_DIR}
+    --xml_output_dir
+    ${CMAKE_BINARY_DIR}/test_results
+  )
+endif()
diff --git a/test/cmake_minimum_required.bash b/test/cmake_minimum_required.bash
new file mode 100755
index 0000000..b190df9
--- /dev/null
+++ b/test/cmake_minimum_required.bash
@@ -0,0 +1,75 @@
+#!/bin/bash
+# Verify that cmake_minimum_required statements have matching version numbers
+
+unset TEST_CMAKE_MIN_REQUIRED_FAILED
+# first argument is root of ign-cmake repository
+if [[ ! -d "$1"  \
+   || ! -a "$1/CMakeLists.txt" \
+   || ! -a "$1/cmake/ignition-config.cmake.in" \
+   || ! -a "$1/config/ignition-cmake-config.cmake.in" ]]; then
+  echo the first argument must be the root of the ign-cmake repository
+  export TEST_CMAKE_MIN_REQUIRED_FAILED=1
+else
+  grep -h '^cmake_minimum_required' \
+    $1/CMakeLists.txt \
+    $1/cmake/ignition-config.cmake.in \
+    $1/config/ignition-cmake-config.cmake.in \
+    | uniq -c \
+    | awk '{ if ($1 != "3") { exit 1 }}' \
+    || \
+    export TEST_CMAKE_MIN_REQUIRED_FAILED=1
+fi
+
+if test "$2" = "--xml_output_dir"; then
+  xml_output_dir=$3
+  if [[ ! -a "${xml_output_dir}" ]]; then
+    mkdir -p "${xml_output_dir}"
+  fi
+  if [[ ! -d "${xml_output_dir}" ]]; then
+    echo If using --xml_output_dir, the 3rd argument must be a directory.
+    exit 1
+  fi
+  if [[ -z ${TEST_CMAKE_MIN_REQUIRED_FAILED} ]]; then
+    cat <<END > ${xml_output_dir}/cmake_minimum_required.xml
+<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="1" failures="0" disabled="0" errors="0" timestamp="$(date '+%Y-%m-%dT%H:%M:%S')" time="0" name="AllTests">
+  <testsuite name="cmake_minimum_required" tests="1" failures="0" disabled="0" errors="0" time="0">
+    <testcase name="make" status="run" time="0" classname="cmake_minimum_required" />
+  </testsuite>
+</testsuites>
+END
+  else
+    cat <<END > ${xml_output_dir}/cmake_minimum_required.xml
+<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="1" failures="1" disabled="0" errors="0" timestamp="$(date '+%Y-%m-%dT%H:%M:%S')" time="0" name="AllTests">
+  <testsuite name="cmake_minimum_required" tests="1" failures="1" disabled="0" errors="0" time="0">
+    <testcase name="make" status="run" time="0" classname="cmake_minimum_required">
+      <failure type="Standard" message="cmake_minimum_required version numbers do not match."><![CDATA[
+END
+  grep -n '^cmake_minimum_required' \
+    $1/CMakeLists.txt \
+    $1/cmake/ignition-config.cmake.in \
+    $1/config/ignition-cmake-config.cmake.in \
+    >> ${xml_output_dir}/cmake_minimum_required.xml
+    cat <<END >> ${xml_output_dir}/cmake_minimum_required.xml
+      ]]></failure>
+    </testcase>
+  </testsuite>
+</testsuites>
+END
+    exit 1
+  fi
+else
+  echo Verify that cmake_minimum_required statements have matching version numbers
+  grep -n '^cmake_minimum_required' \
+    $1/CMakeLists.txt \
+    $1/cmake/ignition-config.cmake.in \
+    $1/config/ignition-cmake-config.cmake.in \
+    | sed -e 's@^@  @'
+  if [[ -z ${TEST_CMAKE_MIN_REQUIRED_FAILED} ]]; then
+    echo --------------------------- Passed ---------------------------
+  else
+    echo --------------------------- Failed ---------------------------
+    exit 1
+  fi
+fi
diff --git a/tools/code_check.sh b/tools/code_check.sh
new file mode 100755
index 0000000..0d803ac
--- /dev/null
+++ b/tools/code_check.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# Jenkins will pass -xml, in which case we want to generate XML output
+xmlout=0
+if test "$1" = "-xmldir" -a -n "$2"; then
+  xmlout=1
+  xmldir=$2
+  mkdir -p $xmldir
+  rm -rf $xmldir/*.xml
+  # Assuming that Jenkins called, the `build` directory is a sibling to the src dir
+  builddir=../build
+else
+  # This is a heuristic guess; not every developer puts the `build` dir in the src dir
+  builddir=./build
+fi
+
+if [ $xmlout -eq 1 ]; then
+  cat << END > $xmldir/code_check.xml
+<?xml version="1.0" encoding="UTF-8"?>
+<results>
+END
+fi
+
+if [ $xmlout -eq 1 ]; then
+  cat << END >> $xmldir/code_check.xml
+</results>
+END
+fi

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/ignition-cmake.git



More information about the debian-science-commits mailing list