Skip to content

Commit f494d73

Browse files
committed
added cmake project guidelines
1 parent 5c4bfaa commit f494d73

File tree

1 file changed

+85
-0
lines changed

1 file changed

+85
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
A Treatise on Open Source C++ Projects using CMake:
2+
3+
Introduction: This document aims to provide a potential strategy regarding a collection of related topics surrounding the ecosystem of open-source C++ libraries. It begins with a list of informal requirements which most successful libraries in most open-source ecosystems meet. Each requirement is accompanied by additional remarks regarding the details of the requirement in the context of C++. After the requirements, the document outlines a series of specific recommendations that open-source C++ library maintainers should follow if they aspire to meet said requirements. Many of the recommendations are connected, in that the benefits yielded by following any one recommendations may depend largely on following one or more other recommendations as well. However, the recommendations do not represent not a strict all-or-nothing proposition.
4+
5+
Scope: The recommendations herein are directed at a subset of C++ projects. Specifically, open-source C++ library projects and applications which leverage them, with an emphasis on platform-agnostic methods. Of course, such a standard could provide value to private C++ projects if it could be easily implemented, such as in new codebases. It would make the borders between projects more consistent and navigable, and allow the developers to use consistent strategies when working between open-source projects and private ones. However, the challenge with private C++ projects is that they often feature legacy code and extenuating circumstances, which are part of the reason many people feel that trying to define any "standards" in C++ is unrealistic.
6+
7+
CMake: Most of the widely used open source libraries of C++ do not implement CMake. This includes, Boost, Qt, and hundreds of others. Most actually predate CMake, and many foundational libraries are actually written in C. As a result, the recommendations is to use CMake to the extent that it provides the benefits cross-platform build comprehension, as well as dependency acquisition and local dependency resolution for the current project. However, the overarching recommendation regarding CMake is to use it's power sparingly and place a high priority on minimizing the complexity of the CMake configuration. Most notably: the interconnection of projects as dependencies within CMake. In the interest of meeting the requirements below, virtually all other dependency resolution features available in CMake are expressly NOT recommended by this document for open-source C++ libraries.
8+
9+
Ecosystem Requirements:
10+
- Default Platform Agnosticism:
11+
Description: A project should extend reasonable effort to support all platforms in all aspects when possible
12+
Reasons:
13+
- Accomodating diversity of OSS development environments and creeds
14+
- Increasing usability of the project in derivative works
15+
- Reduce porting of successful libaries into completely separate projects for each platform
16+
Exceptions:
17+
- Obvious platform-specific code
18+
Explanation: It is both possible and reasonable for many C++ projects to be operable on all three major operating systems: Windows, Linux, and Mac. This includes both the C++ code contained in the library itself, as well as the build process. Within the source code, the C++ compilers all support standard mechanisms for handling most scenarios which require platform-specific. Within the build process, CMake is a meta-build tool which is currently the de-facto standard because it achieves such a uniform and cross-platform build process in Open-source C++ projects.
19+
20+
- Project Self-Sufficiency:
21+
Description: A project should contain virtually all instructions needed to build it automatically
22+
Reasons:
23+
- Continuous Integration Systems
24+
- IDE support
25+
- New potential contributors to the project
26+
Exceptions:
27+
- Obtaining and installing a build system
28+
- Installing a package manager
29+
Explanation: It is both possible and reasonable for C++ projects using to establish a build process which is nearly completely automated, requiring 5-10 commands on a new development machine or CI server (at-most). This includes all activies needed for dependency acquisition and compilation on any platform. Currently within C++, all common build systems and package managers can be installed on all operating systems within 3-5 commands. Once these applications are installed, the build process itself should only require 3-5 additional commands.
30+
31+
- Standardized Local Dependency Caching:
32+
Description: A project system should leverage a standard local cache for resolving dependencies at build time.
33+
Reasons:
34+
- Defining locations of dependencies is often a source of significant complexity and configuration
35+
- Building dependencies separately for each project is often inefficient and unnecessary
36+
Explanation: It is both possible and reasonable to establish a standard local cache for C++ binaries, despite several significant challenges. This is one of the most important factors in the standardization and simplification of build instructions for open-source projects. One important concept to the success of a local cache is the automatic local-only versioning. In the future, a more specific recommendation with more details on this topic will be added to this document, but the versioning should be performed by the project system, without complication to the developer.
37+
38+
- Simple Standardized Acquisition, Compilation, and Caching of Remote Source Code Dependencies:
39+
Description: A project system should make it trivial acquire, compile, and locally cache source code dependencies.
40+
Reasons:
41+
- The most common use cases are simple, uniform, and extremely well known
42+
- Handling the most common use cases in a robust and cross-platform manner manually is non-trivial
43+
- Projects today must handle such dependencies themselves, and do so with varying degrees of effectiveness
44+
Explanation: It is both possible and reasonable to establish a trivial standard mechanism for acquiring and caching remote source code dependencies. Specifically, the most common cases are projects which require a version of dependency which is only available as source code, and for that source code to be available via GIT or tarball. Acquiring, building, and caching such dependencies should be streamlined into a single line of configuration, and executed automatically when necessary. Such a standard mechanism should also operate in a uniform way for both third-party libraries, as well as self-created libraries. This uniformity is achievable by virtue of a standard cache system as described previously.
45+
46+
Recommended Best Practices for Developers:
47+
- Use Cmake to make your C++ project universally operable:
48+
Explanation: CMake is the de-facto standard in Open-Source C++ projects because it provides a platform-independent and build-system-independent interface to the project. This is one of very few ways to meet many of the fundamental requirements for OSS projects described previously.
49+
- Standard CMake Project Layout:
50+
Explanation: There is no formal standard CMake project layout. However, there is an informal standard layout which is as follows:
51+
gitroot
52+
|-- CMakeLists.txt
53+
|
54+
+-- include/
55+
| |
56+
| +-- my_public_interface/
57+
| |-- my_public_interface_header.hpp
58+
|
59+
+-- src/
60+
| |
61+
| +-- some_component/
62+
| |-- CMakeLists.txt
63+
| |-- some_component.cpp
64+
|
65+
+-- test/
66+
|
67+
+-- some_component/
68+
|-- CMakeLists.txt
69+
|-- some_component_test.cpp
70+
71+
- The GIT Repository as the fundamental building block:
72+
Explanation: The introduction of the local cache for dependencies means that whether a dependency is some small library you just broke out of your main project, or a common third-party library like zlib, the project system will find it in the local cache just the same. Without a local-cache, there is a much more a significant time and complexity penalty to breaking small libraries out of bigger projects (which is a very common and healthy process). There are many ways you might reference your library from your main project, and each way comes with nuances. By consolidating to the local cache, it's easier.
73+
74+
- Avoid CMake Features for Dependencies:
75+
Explanation: CMake has multiple mechanisms for referencing other projects, but most of them impose new challenges when used in the context of a loosely coupled open-source ecosystem of independent libraries . The use of a local cache eliminates the need for most of the CMake features in most cases. Also of note, many open-source development workflows involve a single person developing on multiple related library codebases at once on the same machine. The local cache accomodates this tight-loop worklfow very well, as the project system can update the local cache from the local source regularly as the libraries evolve together, without involving an outside package repository or CI system on every minor iteration.
76+
77+
- Avoid GIT Submodules for Dependencies:
78+
Explanation: Much like CMake's dependency management features. The use of a local cache eliminates the need for GIT Submodules.
79+
80+
- Minimize Scripting of the Build Process Outside of CMake:
81+
Explanation: External scripts have historically been a cornerstone of building C++ projects, however they are inherently detrimental to OSS projects in a number of ways. Scripts are generally hard to test and hard to comprehend when someone else wrote them. They represent another language a developer needs to know when trying to comprehend a project. Shell scripts are not cross-platform, and python scripts require python, an extra dependency on the project with version nuances.
82+
83+
- Minimize Scripting of the Build Process Inside of CMake:
84+
Explanation: CMake contains a programming language capable of holding very elaborate build instructions within the CMake files. However, as with all scripts, these are inherently hard to test and hard to read for outsiders. The latest recommendations from the creators of CMake advise against the use of variables altogether in CMake in favor of other first-class mechanisms. Before scripting a build step in CMake, look for a built in feature, and then ask the community about your use case.
85+

0 commit comments

Comments
 (0)