From 5311fc0cef044738ef4e940d082302739cf5750e Mon Sep 17 00:00:00 2001 From: Joshua Potter Date: Thu, 21 Dec 2023 16:54:49 -0500 Subject: [PATCH] Migrate clang project to fuller CMake configuration. --- .gitignore | 1 - compile_commands.json | 1 + flake.nix | 4 +-- specs/clang/runner | 16 ++++++++- specs/clang/spec.json | 6 ++++ specs/clang/template/.gitignore | 3 +- specs/clang/template/CMakeLists.txt | 32 ++++++++++++++++-- specs/clang/template/README.md | 38 +++++++++++++++++++--- specs/clang/template/compile_commands.json | 1 + specs/clang/template/flake.nix | 21 +++++++++++- specs/clang/template/include/hello.h | 6 ++++ specs/clang/template/main.c | 4 +-- specs/clang/template/src/CMakeLists.txt | 5 +++ specs/clang/template/src/hello.c | 8 +++++ specs/clang/template/test/CMakeLists.txt | 5 +++ specs/clang/template/test/test_hello.c | 3 ++ 16 files changed, 137 insertions(+), 17 deletions(-) create mode 120000 compile_commands.json create mode 100644 specs/clang/spec.json create mode 120000 specs/clang/template/compile_commands.json create mode 100644 specs/clang/template/include/hello.h create mode 100644 specs/clang/template/src/CMakeLists.txt create mode 100644 specs/clang/template/src/hello.c create mode 100644 specs/clang/template/test/CMakeLists.txt create mode 100644 specs/clang/template/test/test_hello.c diff --git a/.gitignore b/.gitignore index 4dba1a9..8469de9 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,5 @@ Testing Makefile cmake_install.cmake install_manifest.txt -compile_commands.json CTestTestfile.cmake _deps diff --git a/compile_commands.json b/compile_commands.json new file mode 120000 index 0000000..2cb3529 --- /dev/null +++ b/compile_commands.json @@ -0,0 +1 @@ +build/Debug/compile_commands.json \ No newline at end of file diff --git a/flake.nix b/flake.nix index 5a1cb1c..c8b1a02 100644 --- a/flake.nix +++ b/flake.nix @@ -20,7 +20,7 @@ in { packages = { - release = pkgs.stdenv.mkDerivation { + app = pkgs.stdenv.mkDerivation { pname = "bootstrap"; src = ./.; version = "0.1.3"; @@ -39,7 +39,7 @@ if [ -z "$BOOTSTRAP_ROOT_DIR" ]; then export BOOTSTRAP_ROOT_DIR="${./specs}" fi - exec ${self.packages.${system}.release}/bootstrap "$@" + exec ${self.packages.${system}.app}/bin/bootstrap "$@" ''; }; devShells.default = pkgs.mkShell.override { diff --git a/specs/clang/runner b/specs/clang/runner index edc5741..a1c9cad 100755 --- a/specs/clang/runner +++ b/specs/clang/runner @@ -30,7 +30,7 @@ fi # to ensure we never evaluate to root (i.e. `/`). That should never actually # happen but a good habit to establish nonetheless. function cleanup { - rm -r "/tmp/bs.clang/$(basename "$BUILD")" + yes | rm -r "/tmp/bs.clang/$(basename "$BUILD")" } trap cleanup EXIT @@ -47,6 +47,20 @@ find "$BUILD" -type f -execdir chmod 644 {} + find "$BUILD" -type d -execdir chmod 755 {} + chmod 755 "$BUILD"/.githooks/pre-commit +# Create new subdirectories for out-of-source builds. Each should be initialized +# with `CMAKE_BUILD_TYPE` set appropriately during configuration, e.g. +# `cd build/Debug && cmake -DCMAKE_BUILD_TYPE=Debug ../..` +mkdir -p "$BUILD"/build/{Debug,Release} + +# ============================================================ +# REWRITES +# ============================================================ + +for file in flake.nix {,src/,test/}CMakeLists.txt +do + sed -i "s//$NAME/g" "$BUILD/$file" +done + # ============================================================ # EPILOGUE # ============================================================ diff --git a/specs/clang/spec.json b/specs/clang/spec.json new file mode 100644 index 0000000..4be1e50 --- /dev/null +++ b/specs/clang/spec.json @@ -0,0 +1,6 @@ +{ + "name": { + "type": "line", + "prompt": "Name> " + } +} diff --git a/specs/clang/template/.gitignore b/specs/clang/template/.gitignore index 2691046..8c115c0 100644 --- a/specs/clang/template/.gitignore +++ b/specs/clang/template/.gitignore @@ -5,7 +5,7 @@ /.direnv/ # The directory containing all build outputs. -/dist/ +/build/ # The directory generated by `Doxygen`. /docs/ @@ -25,6 +25,5 @@ Testing Makefile cmake_install.cmake install_manifest.txt -compile_commands.json CTestTestfile.cmake _deps diff --git a/specs/clang/template/CMakeLists.txt b/specs/clang/template/CMakeLists.txt index ee2f214..5c00635 100644 --- a/specs/clang/template/CMakeLists.txt +++ b/specs/clang/template/CMakeLists.txt @@ -1,7 +1,33 @@ cmake_minimum_required(VERSION 3.15) +project("" VERSION 0.1.0) -project(App VERSION 0.1.0) +# The primary executable. +add_executable("" main.c) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +# Include the cmake commands found in `src`. This subdirectory is responsible +# for linking the other project source files to our executable. +add_subdirectory(src) -add_executable(a.out main.c) +# An example on linking additional libraries. In this case, links `math`. +target_link_libraries("" PUBLIC m) + +# Location of different headers to include when compiling the executable. +target_include_directories("" PUBLIC include) + +if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + set_target_properties( + "" PROPERTIES + # The top-level `compile_commands.json` is a symbolic link to this file. + EXPORT_COMPILE_COMMANDS ON + # Enable so that tests can link against the primary executable. + ENABLE_EXPORTS ON + ) + + # Turns on testing. This must be done at the root `CMakeLists.txt` file. If + # looking for additional testing configuration, consider using + # `include(CTest)` instead. + enable_testing() + + # Add test files to our cmake configuration. + add_subdirectory(test) +endif() diff --git a/specs/clang/template/README.md b/specs/clang/template/README.md index dbcb7d0..a76f400 100644 --- a/specs/clang/template/README.md +++ b/specs/clang/template/README.md @@ -8,17 +8,35 @@ can be used to launch a dev shell upon entering this directory (refer to $ nix develop ``` +## Building + +We use [CMake](https://cmake.org/) (version 3.27.7) to build the project. When +first starting the project, we recommend running the following commands: +```bash +$ mkdir -p build/{Debug,Release} +$ (cd build/Debug && cmake -DCMAKE_BUILD_TYPE=Debug ../..) +$ (cd build/Release && cmake -DCMAKE_BUILD_TYPE=Release ../..) +``` +This will create a CMake cache file in each subdirectory with the build types +set. Now you can build a `Debug` or `Release` variant by navigating to the +corresponding subdirectory and running: +```bash +$ cmake --build . +``` + ## Language Server The [clangd](https://clangd.llvm.org/) LSP (version 14.0.6) is included in this flake. The [codelldb](https://github.com/vadimcn/codelldb) VSCode plugin is also included to interface with the LSP. Note this plugin, despite its name, is compatible with other editors (e.g. neovim). To configure, refer to your -editor's documentation. To use the LSP across files, a +editor's documentation. + +To use the LSP across files, a [compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) -must be generated. [CMake](https://cmake.org/) (version 3.27.7) is included in -this flake with `CMAKE_EXPORT_COMPILE_COMMANDS` already set from the -`CMakeLists.txt` file. +must be generated. The `CMakeLists.txt` file already enables this in the Debug +configuration type. A top-level `compile_commands.json` symbolic link already +exists and points to this generated database. ## Documentation @@ -29,12 +47,22 @@ running: $ doxygen ``` +## Testing + +We use [CTest](https://cmake.org/cmake/help/latest/module/CTest.html) (version +3.27.7) for unit testing. To run the tests, navigate to `build/Debug` and type +the following: +```bash +$ cmake --build . +$ make test +``` + ## Formatting Formatting depends on the [clang-format](https://clang.llvm.org/docs/ClangFormat.html) (version 14.0.6) tool. Refer to `.clang-format` for default formatting options. A `pre-commit` hook is included in `.githooks` that can be used to format all -`*.c` and `*.h` files prior to commit. Install via: +`*.c(pp)?` and `*.h(pp)?` files prior to commit. Install via: ```bash $ git config --local core.hooksPath .githooks/ ``` diff --git a/specs/clang/template/compile_commands.json b/specs/clang/template/compile_commands.json new file mode 120000 index 0000000..2cb3529 --- /dev/null +++ b/specs/clang/template/compile_commands.json @@ -0,0 +1 @@ +build/Debug/compile_commands.json \ No newline at end of file diff --git a/specs/clang/template/flake.nix b/specs/clang/template/flake.nix index 2c7cdee..666609a 100644 --- a/specs/clang/template/flake.nix +++ b/specs/clang/template/flake.nix @@ -15,7 +15,7 @@ nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; }; - outputs = { nixpkgs, flake-utils, ... }: + outputs = { self, nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; @@ -25,6 +25,25 @@ ''; in { + packages = { + app = pkgs.stdenv.mkDerivation { + pname = ""; + src = ./.; + version = "0.1.0"; + nativeBuildInputs = with pkgs; [ cmake ]; + buildPhase = '' + cmake -DCMAKE_BUILD_TYPE=Release . + cmake --build . + ''; + installPhase = '' + mkdir -p $out/bin + cp ./"" $out/bin + ''; + }; + + default = self.packages.${system}.app; + }; + devShells.default = pkgs.mkShell.override { # https://nixos.wiki/wiki/Using_Clang_instead_of_GCC stdenv = pkgs.clangStdenv; diff --git a/specs/clang/template/include/hello.h b/specs/clang/template/include/hello.h new file mode 100644 index 0000000..151a8c3 --- /dev/null +++ b/specs/clang/template/include/hello.h @@ -0,0 +1,6 @@ +#ifndef _HELLO_H +#define _HELLO_H + +int hello_world(); + +#endif /* _HELLO_H */ diff --git a/specs/clang/template/main.c b/specs/clang/template/main.c index 897b9c8..9ac231d 100644 --- a/specs/clang/template/main.c +++ b/specs/clang/template/main.c @@ -1,3 +1,3 @@ -#include +#include "hello.h" -int main(int argc, char *argv[argc + 1]) { return EXIT_SUCCESS; } +int main(int argc, char *argv[argc + 1]) { return hello_world(); } diff --git a/specs/clang/template/src/CMakeLists.txt b/specs/clang/template/src/CMakeLists.txt new file mode 100644 index 0000000..020bfdd --- /dev/null +++ b/specs/clang/template/src/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources( + "" PUBLIC + hello.c +) + diff --git a/specs/clang/template/src/hello.c b/specs/clang/template/src/hello.c new file mode 100644 index 0000000..b7f8656 --- /dev/null +++ b/specs/clang/template/src/hello.c @@ -0,0 +1,8 @@ +#include "hello.h" + +#include + +int hello_world() { + printf("Hello, world!\n"); + return 0; +} diff --git a/specs/clang/template/test/CMakeLists.txt b/specs/clang/template/test/CMakeLists.txt new file mode 100644 index 0000000..4b596dc --- /dev/null +++ b/specs/clang/template/test/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(test-hello test_hello.c) +target_link_libraries(test-hello PRIVATE "") +target_include_directories(test-hello PRIVATE "") + +add_test(NAME hello COMMAND ./test-hello) diff --git a/specs/clang/template/test/test_hello.c b/specs/clang/template/test/test_hello.c new file mode 100644 index 0000000..8a1b3fa --- /dev/null +++ b/specs/clang/template/test/test_hello.c @@ -0,0 +1,3 @@ +#include "hello.h" + +int main(int argc, char **argv) { return hello_world(); }