A template for modern C projects. Uses Conan for dependency management and Meson as the build system.
This project template includes:
- Convenient Python scripts for managing the build environment.
- Different layouts for library and application projects.
- Automatic versioning through introspection of the latest Git tag.
- Set by creating a Git tag (the name of the tag is the version).
- Accessible within the code via the "version" namespace.
- The default version "0.0.0" is used when there are no Git tags.
- Configuration files for LLVM C tools (clangd, clang-format, and clang-tidy).
- clangd -- A language server configured by the ".clangd" file.
- clang-format -- A code formatter configured by the ".clang-format" file.
- clang-tidy -- A code linter configured by the ".clang-tidy" file.
- Dependency management through Conan.
- Add and remove dependencies and binaries by editing the "binary_config.json" file.
- GoogleTest added by default.
- A Meson build file that receives dependency and binary information from Conan.
- A configuration file for the code formatting feature of muon (an implementation of Meson with a builtin code formatter and static analyzer).
- An automatically generated README.md file with detailed build instructions.
- A gitignore file for C and Python.
- An example sub-project to demo how other programs can use your project (if it's a library).
Install Git and Python:
- Git (distributed version control)
- Python (interpreted scripting language)
- Select the "Add python.exe to PATH" option.
Install one of the following C compilers:
- Visual Studio's C compiler (MSVC)
- Select the "Desktop development with C " option.
- MinGW (GCC for Windows)
- Mark "mingw32-gcc-g " for installation. Then select "Apply Changes" within the "Installation" dropdown.
- Add the MinGW bin directory (C:\MinGW\bin\) to your PATH.
Install Homebrew (package manager for Mac) by opening a terminal and entering the following command:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Use Homebrew to install Git, Python, and GCC (C compiler):
brew install git python gcc
sudo apt install git python3 build-essential
sudo pacman -S git python base-devel
Open command prompt (Windows) or a shell (Linux & Mac) and enter the commands below. The template will be downloaded to the current working directory.
git clone https://github.com/cshmookler/cpp_template.git
cd cpp_template
Any text editor (Notepad, TextEdit, Nano, Vim, etc.) can be used as long as the file name and format are not changed.
notepad template_config.ini
open -t template_config.ini
nano template_config.ini
Use Python to execute the "config.py" script. Use command prompt (Windows) or a shell (Mac & Linux) so errors are shown.
python config.py
If errors occur, troubleshoot to isolate the issue and repeat steps 2-4.
Use Python to execute the "build.py" script. Use command prompt (Windows) or a shell (Mac & Linux) so errors are shown.
python build.py
The "build.py" script updates the build system, active profiles, dependencies, and binary configuration before building. If none of these are modified (the build system is the same, the active profile is not changed, the "dependency_config.json" file is untouched, and the "binary_config.json" file is untouched), then directly invoking the Meson backend (Ninja) is the fastest way to rebuild binaries.
cd build
ninja
Dependency configuration information is stored in the "dependency_config.json" file. This JSON file contains a dictionary of dependency names associated with information describing them. The listed dependencies are installed by Conan when the project is built.
An example of a "dependency_config.json" file annotated with comments prefixed with "//" is shown below. This example file installs GoogleTest 1.14.0 (dynamically) and Zlib 1.3.1 (no link preference) from Conan Center.
{ //
"gtest": { // dependency name
"version": "1.14.0", // * dependency version for Conan (optional)
"user": "", // * dependency user for Conan (optional)
// "" -- (default) search Conan Center for this dependency
"channel": "", // * dependency channel for Conan (optional)
// "" -- (default) search Conan Center's default channel for this dependency
"dynamic": true // * link method (optional)
// null -- (default) no linking preference
// true -- prefer dynamic linking
// false -- prefer static linking
}, //
"zlib": { // dependency name
"version": "1.3.1", // * dependency version for Conan (optional)
"user": "", // * dependency user for Conan (optional)
// "" -- (default) search Conan Center for this dependency
"channel": "", // * dependency channel for Conan (optional)
// "" -- (default) search Conan Center's default channel for this dependency
"dynamic": null // * link method (optional)
// null -- (default) no linking preference
// true -- prefer dynamic linking
// false -- prefer static linking
} //
} //
Note: Read the official Conan documentation for more information on dependency versions, users, and channels.
Browse Conan Center (the Conan central repository) for dependencies. Use the search bar to find the "name/version" of the dependencies you would like to add (example: "boost/1.85.0").
Add a new entry to the "dependency_config.json" file like in the example below. Examples of dependencies in this file are shown in the example above.
{
// ...
"boost": {
"version": "1.14.0"
}
// ...
}
Note: Installed dependencies must be explicitly linked with specific binaries. Read the next section for information on linking dependencies.
Note: Existing build files may need to be removed for changes to take effect.
Open the "dependency.json" file and remove the cooresponding entries.
Note: All references to the removed dependency in the binary configuration file must also be removed or the next build will fail.
Note: Existing build files may need to be removed for changes to take effect.
Binary configuration information is stored in the "binary_config.json" file. This JSON file contains a dictionary of binary names associated with information describing the corresponding binaries.
An example of a "binary_config.json" file annotated with comments prefixed with "//" is shown below. This example file describes a library named "cpp_template" that depends on Zlib and a test named "version" that depends on GoogleTest. Using this example requires that GoogleTest and Zlib be listed in the dependency configuration file.
{ //
"cpp_template": { // binary name
"type": "library", // * binary type:
// "application" -- generate an executable
// "library" -- generate a library
// "test" -- generate and execute a test
"dependencies": { // * dependencies (optional)
"zlib": { // * dependency (example: Zlib)
"zlib": true // * component (example: "zlib") (optional):
// true -- (default) link with this component
// false -- do not link with this component
} //
}, //
"headers": [ // * header file paths (only for libraries)
[ // * header file path:
"cpp_template", // (represented as a list of path components)
"version.hpp" //
] //
], //
"sources": [ // * source file paths
[ // * source file path:
"src", // (represented as a list of path components)
"version.cpp" //
] //
], //
// "main": ["src", "main.cpp"] // * 'main' function file path:
// (only for applications and tests)
// (represented as a list of path components)
}, //
"version": { // binary name
"type": "test", // * binary type:
// "application" -- generate an executable
// "library" -- generate a library
// "test" -- generate and execute a test
"dependencies": { // * dependencies (optional)
"gtest": { // * dependency (example: GoogleTest)
"gtest": true, // * component (example: "gtest") (optional):
// true -- (default) link with this component
// false -- do not link with this component
"gtest_main": true, // * component (example: "gtest_main") (optional):
// true -- (default) link with this component
// false -- do not link with this component
"gmock": false, // * component (example: "gmock") (optional):
// true -- (default) link with this component
// false -- do not link with this component
"gmock_main": false // * component (example: "gmock_main") (optional):
// true -- (default) link with this component
// false -- do not link with this component
} //
}, //
"sources": [ // * source file paths
[ // * source file path:
"src", // (represented as a list of path components)
"version.test.cpp" //
], //
[ // * source file path:
"src", // (represented as a list of path components)
"version.cpp" //
] //
] //
} //
} //
Some dependencies contain multiple components that can be individually enabled or disabled. The list of components for dependencies is automatically updated after each build.
To update the lists of dependency components without building, use Python to execute the "update_deps.py" script. Use command prompt (Windows) or a shell (Mac & Linux) so errors are shown.
python update_deps.py
If the build system is changed (the "binary_config.json", "dependency_config.json", "meson.build", or "conanfile.py" files are edited) then the existing build files may need to be regenerated. Removing the build files forces them to be regenerated when the project is built.
Use Python to execute the "clean.py" script. Use command prompt (Windows) or a shell (Mac & Linux) so errors are shown.
python clean.py
Clearing the Conan cache removes all downloaded dependencies. Required dependencies will be re-downloaded when the project is built.
Use Python to execute the "clear_cache.py" script. Use command prompt (Windows) or a shell (Mac & Linux) so errors are shown.
python clear_cache.py
The active Conan profiles list system architecture, operating system, C compiler, and other configuration information for Conan. All profiles are stored in the "profiles" directory and have a ".profile" extension. The default profile ("default.profile") is automatically generated if it does not exist.
Conan uses two active profiles: build and host. The build profile defines the platform where the binaries are built, and the host profile defines the platform where the binaries are executed. Using different build and host profiles is useful for cross-compiling.
The paths to the active profiles are stored in the "profiles.ini" configuration file. If either of those profiles do not exist when the project is built, then the default profile is used instead.
To view the paths to the profiles that will actually be used when the project is built, use Python to execute the "profiles.py" script without any arguments. Use command prompt (Windows) or a shell (Mac & Linux) to show output and display errors.
python profiles.py
To change the active build profile, use Python to execute the "profiles.py" script with the new profile path following the "--build" option. Use command prompt (Windows) or a shell (Mac & Linux) to show output and display errors. The example below sets the active build profile to "new-build.profile".
python profiles.py --build new-build.profile
Note: The new profile must exist in the "profiles" directory else the default profile will be used instead.
To change the active host profile, use the "--host" option instead. The example below sets the active host profile to "new-host.profile".
python profiles.py --host new-host.profile
The default Conan profile is automatically regenerated if it is an active profile but does not exist when the project is built.
Delete the "default.profile" file in the "profiles" directory. Delete the "profiles.ini" file as well to ensure that the default profile is selected as an active profile. Use python to execute the "profiles.py" script without passing any arguments. Use command prompt (Windows) or a shell (Mac & Linux) to show output and display errors.
python profiles.py
Installing a project exports its source files and generated binaries to the Conan cache so that other projects can use it as a dependency.
Use Python to execute the "install.py" script. Use command prompt (Windows) or a shell (Mac & Linux) so errors are shown.
python install.py
- Proper GoogleTest integration.
-
Some dependencies fail to build from sourceResolved by remote recipes adapting to Conan 2. - Provide options for controlling what modules are linked from dependencies.
- Provide a more intuitive method for adding more executables, libraries and tests.
- Generate different "conanfile.py" files for different package types.
- Provide more detailed documentation.
- Allow regeneration of the default Conan profile.
- Use Jinja for templating.
- Add support for different host and build profiles.
- Add option for static or dynamic linking of dependencies.
- Add build targets by editing a configuration file instead of manually editing the "meson.build" file.
- Record dependency component versions independently from the overall dependency version.
- Add tests for verifying the integrity and functionality of this template.
- Make Conan and Git optional (for a stripped-down template with minimal features).
- List dependency version, user, and channel
and recipe revisionseparately from the dependency name within the binary_config.json file. - Improve documentation.