├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake ├── BuildHelpers.cmake └── Config.cmake.in ├── default.nix ├── flake.lock ├── flake.nix └── src ├── CMakeLists.txt ├── simple.cc ├── simple.h ├── simple_test.cc └── what_time.cc /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Build 35 | build 36 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake References: https://github.com/Lectem/cpp-boilerplate/blob/master/CMakeLists.txt 2 | 3 | cmake_minimum_required(VERSION 3.17) 4 | 5 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) 6 | message(FATAL_ERROR "Do not build in-source. Please remove CMakeCache.txt and the CMakeFiles/ directory. Then build out-of-source.") 7 | endif() 8 | 9 | project(cpp-example 10 | VERSION 0.1.0 11 | LANGUAGES C CXX) 12 | 13 | set(CMAKE_CXX_STANDARD 20) 14 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 15 | if(APPLE) 16 | add_compile_options(-mmacosx-version-min=10.15) 17 | endif() 18 | ############################ 19 | ## Modules and scripts ## 20 | ############################ 21 | 22 | # Standard CMake modules 23 | 24 | include(CTest) # Must be called before adding tests but after calling project(). This automatically calls enable_testing() and configures ctest targets when using Make/Ninja 25 | include(CMakeDependentOption) # This is a really useful scripts that creates options that depends on other options. It can even be used with generator expressions ! 26 | include(GNUInstallDirs) # This will define the default values for installation directories (all platforms even if named GNU) 27 | include(InstallRequiredSystemLibraries) # Tell CMake that the `install` target needs to install required system libraries (eg: Windows SDK) 28 | include(CMakePackageConfigHelpers) # Helper to create relocatable packages 29 | 30 | 31 | # Custom modules and scripts 32 | 33 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") # Make our cmake scripts available 34 | 35 | include(BuildHelpers) # Helpers for writing cmake files 36 | 37 | ############### 38 | ## Options ## 39 | ############### 40 | 41 | option(ENABLE_INSTALL 42 | "Should ${PROJECT_NAME} be added to the install list? Useful if included using add_subdirectory." ON) 43 | option(ENABLE_TESTING "Should unit tests be compiled." ON) 44 | 45 | set(${PROJECT_NAME}_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" 46 | CACHE STRING "Path to install ${PROJECT_NAME} Config*.cmake files to.") 47 | 48 | #################### 49 | ## Dependencies ## 50 | #################### 51 | 52 | find_package(spdlog REQUIRED) 53 | find_package(absl REQUIRED) 54 | 55 | if(ENABLE_TESTING) 56 | find_package(GTest REQUIRED) 57 | include(GoogleTest) 58 | enable_testing() 59 | endif() 60 | 61 | ############### 62 | ## Targets ## 63 | ############### 64 | 65 | # Use the project root to find includes 66 | include_directories(${PROJECT_SOURCE_DIR}) 67 | 68 | add_subdirectory(src) 69 | 70 | ############### 71 | ## Packaging ## 72 | ############### 73 | 74 | if(ENABLE_INSTALL) 75 | # Use version checking helper provided by CMake so that users can 76 | # safely use a version number in their find_package calls 77 | write_basic_package_version_file( 78 | ${PROJECT_NAME}ConfigVersion.cmake 79 | VERSION ${PROJECT_VERSION} 80 | COMPATIBILITY SameMajorVersion) 81 | 82 | configure_package_config_file( 83 | ${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in 84 | ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake 85 | INSTALL_DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKEDIR} 86 | NO_SET_AND_CHECK_MACRO 87 | NO_CHECK_REQUIRED_COMPONENTS_MACRO) 88 | 89 | install( 90 | TARGETS what_time simple 91 | EXPORT ${PROJECT_NAME}_Targets 92 | INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 93 | 94 | install(DIRECTORY src 95 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 96 | FILES_MATCHING PATTERN *.h) 97 | 98 | # This time, install all the exported targets under the 99 | # ${PROJECT_NAME}_Targets name. 100 | install( 101 | EXPORT ${PROJECT_NAME}_Targets 102 | NAMESPACE ${PROJECT_NAME}:: 103 | FILE ${PROJECT_NAME}Targets.cmake 104 | DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKEDIR}) 105 | 106 | # So far we only installed the exported targets, now install the package config files. 107 | # 108 | # If you do not list headers in the PUBLIC_HEADER property, you will need to copy them using 109 | # `install(FILES)` or `install(DIRECTORY)` too. 110 | # 111 | # In that case, you can use CMAKE_INSTALL_INCLUDEDIR as the base destination path. 112 | install(FILES 113 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake 114 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake 115 | DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKEDIR}) 116 | endif() 117 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Break Yang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![built with nix](https://builtwithnix.org/badge.svg)](https://builtwithnix.org) 2 | 3 | # A Nix Basde C++ Project Template 4 | 5 | This repo is used as a template for creating C++ projects. 6 | 7 | 1. It provides a Nix-based development environment (devShell). 8 | 9 | To activate the `devShell`, run `nix develop`. 10 | 2. It provides a working `CMakeLists.txt` that supports unit testing and installation. 11 | 3. It provides a `default.nix` as a starting point to package your awesome C++ projects for others to depend on. 12 | 13 | # Details 14 | 15 | You can find the details about how this template is created (and 16 | therefore how to customize it to your needs) in this [blog 17 | post](https://www.breakds.org/post/nix-based-c++-workflow/). 18 | -------------------------------------------------------------------------------- /cmake/BuildHelpers.cmake: -------------------------------------------------------------------------------- 1 | include(CMakeParseArguments) 2 | 3 | function(make_cc_test) 4 | if (NOT ENABLE_TESTING) 5 | return() 6 | endif() 7 | 8 | cmake_parse_arguments(MAKE_CC_TEST 9 | "" 10 | "NAME" 11 | "SRCS;DEPS;DATA" 12 | ${ARGN}) 13 | 14 | set(_NAME "${MAKE_CC_TEST_NAME}") 15 | 16 | add_executable(${_NAME}) 17 | target_sources(${_NAME} PRIVATE ${MAKE_CC_TEST_SRCS}) 18 | target_link_libraries(${_NAME} 19 | PRIVATE ${MAKE_CC_TEST_DEPS} gtest gmock gtest_main) 20 | gtest_discover_tests(${_NAME}) 21 | 22 | 23 | file(RELATIVE_PATH _DEST_DIR ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) 24 | install(TARGETS ${_NAME} DESTINATION tests/${_DEST_DIR}) 25 | foreach (_DATA_FILE ${MAKE_CC_TEST_DATA}) 26 | get_filename_component(SUBPATH ${_DATA_FILE} DIRECTORY) 27 | install(FILES ${_DATA_FILE} DESTINATION tests/${_DEST_DIR}/${SUBPATH}) 28 | configure_file(${_DATA_FILE} ${_DATA_FILE} COPYONLY) 29 | endforeach() 30 | 31 | endfunction() 32 | -------------------------------------------------------------------------------- /cmake/Config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | # Required so that on windows Release and RelWithDebInfo can be used instead of default fallback which is Debug 4 | # See https://gitlab.kitware.com/cmake/cmake/issues/20319 5 | 6 | set(CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL MinSizeRel RelWithDebInfo Release Debug "") 7 | set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO RelWithDebInfo Release MinSizeRel Debug "") 8 | set(CMAKE_MAP_IMPORTED_CONFIG_RELEASE Release RelWithDebInfo MinSizeRel Debug "") 9 | 10 | # If your package depends an another one, you MUST specify it here 11 | include(CMakeFindDependencyMacro) 12 | find_dependency(spdlog REQUIRED) 13 | find_dependency(absl REQUIRED) 14 | 15 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") 16 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , llvmPackages_11 3 | , cmake 4 | , spdlog 5 | , abseil-cpp }: 6 | 7 | llvmPackages_11.stdenv.mkDerivation rec { 8 | pname = "cpp-examples"; 9 | version = "0.1.0"; 10 | 11 | src = ./.; 12 | 13 | nativeBuildInputs = [ cmake ]; 14 | buildInputs = [ spdlog abseil-cpp ]; 15 | 16 | cmakeFlags = [ 17 | "-DENABLE_TESTING=OFF" 18 | "-DENABLE_INSTALL=ON" 19 | ]; 20 | 21 | meta = with lib; { 22 | homepage = "https://github.com/nixvital/nix-based-cpp-starterkit"; 23 | description = '' 24 | A template for Nix based C++ project setup."; 25 | ''; 26 | licencse = licenses.mit; 27 | platforms = with platforms; linux ++ darwin; 28 | maintainers = [ maintainers.breakds ]; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1669833724, 6 | "narHash": "sha256-/HEZNyGbnQecrgJnfE8d0WC5c1xuPSD2LUpB6YXlg4c=", 7 | "owner": "NixOS", 8 | "repo": "nixpkgs", 9 | "rev": "4d2b37a84fad1091b9de401eb450aae66f1a741e", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "NixOS", 14 | "ref": "22.11", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "root": { 20 | "inputs": { 21 | "nixpkgs": "nixpkgs", 22 | "utils": "utils" 23 | } 24 | }, 25 | "utils": { 26 | "locked": { 27 | "lastModified": 1623875721, 28 | "narHash": "sha256-A8BU7bjS5GirpAUv4QA+QnJ4CceLHkcXdRp4xITDB0s=", 29 | "owner": "numtide", 30 | "repo": "flake-utils", 31 | "rev": "f7e004a55b120c02ecb6219596820fcd32ca8772", 32 | "type": "github" 33 | }, 34 | "original": { 35 | "owner": "numtide", 36 | "repo": "flake-utils", 37 | "type": "github" 38 | } 39 | } 40 | }, 41 | "root": "root", 42 | "version": 7 43 | } 44 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "A template for Nix based C++ project setup."; 3 | 4 | inputs = { 5 | # Pointing to the current stable release of nixpkgs. You can 6 | # customize this to point to an older version or unstable if you 7 | # like everything shining. 8 | # 9 | # E.g. 10 | # 11 | # nixpkgs.url = "github:NixOS/nixpkgs/unstable"; 12 | nixpkgs.url = "github:NixOS/nixpkgs/22.11"; 13 | 14 | utils.url = "github:numtide/flake-utils"; 15 | }; 16 | 17 | outputs = { self, nixpkgs, ... }@inputs: inputs.utils.lib.eachSystem [ 18 | # Add the system/architecture you would like to support here. Note that not 19 | # all packages in the official nixpkgs support all platforms. 20 | "x86_64-linux" "i686-linux" "aarch64-linux" "x86_64-darwin" 21 | ] (system: let 22 | pkgs = import nixpkgs { 23 | inherit system; 24 | 25 | # Add overlays here if you need to override the nixpkgs 26 | # official packages. 27 | overlays = []; 28 | 29 | # Uncomment this if you need unfree software (e.g. cuda) for 30 | # your project. 31 | # 32 | # config.allowUnfree = true; 33 | }; 34 | in { 35 | devShells.default = pkgs.mkShell rec { 36 | # Update the name to something that suites your project. 37 | name = "my-c++-project"; 38 | 39 | packages = with pkgs; [ 40 | # Development Tools 41 | llvmPackages_14.clang 42 | cmake 43 | cmakeCurses 44 | 45 | # Development time dependencies 46 | gtest 47 | 48 | # Build time and Run time dependencies 49 | spdlog 50 | abseil-cpp 51 | ]; 52 | 53 | # Setting up the environment variables you need during 54 | # development. 55 | shellHook = let 56 | icon = "f121"; 57 | in '' 58 | export PS1="$(echo -e '\u${icon}') {\[$(tput sgr0)\]\[\033[38;5;228m\]\w\[$(tput sgr0)\]\[\033[38;5;15m\]} (${name}) \\$ \[$(tput sgr0)\]" 59 | ''; 60 | }; 61 | 62 | packages.default = pkgs.callPackage ./default.nix {}; 63 | }); 64 | } 65 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(what_time) 2 | target_sources(what_time PRIVATE what_time.cc) 3 | target_link_libraries(what_time PRIVATE absl::time spdlog::spdlog) 4 | 5 | add_library(simple) 6 | target_sources(simple 7 | PUBLIC 8 | $ 9 | $ 10 | PRIVATE simple.cc) 11 | 12 | if(ENABLE_TESTING) 13 | MAKE_CC_TEST( 14 | NAME simple_test 15 | SRCS simple_test.cc 16 | DEPS simple) 17 | endif() 18 | -------------------------------------------------------------------------------- /src/simple.cc: -------------------------------------------------------------------------------- 1 | namespace simple { 2 | 3 | int Subtract(int a, int b) { 4 | return a - b; 5 | } 6 | 7 | } // namespace toy 8 | -------------------------------------------------------------------------------- /src/simple.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace simple { 4 | 5 | template 6 | auto Add(const ValueType &a, const ValueType &b) -> ValueType { 7 | return a + b; 8 | } 9 | 10 | int Subtract(int a, int b); 11 | 12 | } // namespace simple 13 | -------------------------------------------------------------------------------- /src/simple_test.cc: -------------------------------------------------------------------------------- 1 | #include "src/simple.h" 2 | 3 | #include "gtest/gtest.h" 4 | #include "gmock/gmock.h" 5 | 6 | TEST(SimpleTest, OnePlusOneEqualsTwo) { 7 | EXPECT_EQ(2, simple::Add(1, 1)); 8 | } 9 | -------------------------------------------------------------------------------- /src/what_time.cc: -------------------------------------------------------------------------------- 1 | #include "absl/time/time.h" 2 | #include "absl/time/clock.h" 3 | #include "spdlog/spdlog.h" 4 | 5 | int main(int argc, char ** argv) { 6 | absl::Time time = absl::Now(); 7 | spdlog::info("Currently, the UTC time is {}", 8 | absl::FormatTime(time, absl::UTCTimeZone())); 9 | return 0; 10 | } 11 | --------------------------------------------------------------------------------