Skip to content

It's an boilerplate for usage of c/c++ compilers, linters, formatters (the settings) in a future project. Check out the docs below to be in actual tune!

License

Notifications You must be signed in to change notification settings

Dmitriy-Frostoff/boilerplate-c_cpp-compilers_linters_formatters

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

boilerplate-c_cpp-compilers_linters_formatters

It's an boilerplate for usage of C/C++ and it's tools in a future project. Check out the docs below to be in an actual tune!


!Important

It was used only at actual Windows 10 x64 (TODO! check the Linux)!

Do all the steps from C/C++ for Visual Studio Code before usage.

!note: eslint, prettier, execa are not necessary for C++ project! (and by the way husky with commitlint too, but they're very convinient for following Git-flow principles). So just take what you really need from the project.

!Strongly required the next list of tools to be used / installed / present at your PC:

optional:

note: It's a common practice for C/C++ languages tools collect them and place apart of your system (mean C:/Program Files etc). E.g. C:/Tools. It's expected in the project C:/Tools with adding to the Windows 's path environment variables.

Currently (Windows 10 x64):

  • C:/Tools/msys64/ucrt64/bin - GCC, the GNU Compiler Collection;
  • C:/Tools/LLVM/bin - The LLVM Compiler Infrastructure Project;

Also this pathes must be added to the PATH environment (How to: Add Tool Locations to the PATH Environment Variable).

The boilerplate structure and brief descriptions:

  • .husky - folder for husky's hooks (with hooks config);
  • .vscode/settings.json - settings for appropraite work of C/C++ core in the project at first and then (optionally) the ESlint and Prettier VSCode extensions in a project (with a help of Format Code Action extension). There're settings and scripts for a usage of the configs (and ignore) files in the project (i.e. links to ones config files) and there's end-of-line(EOF) property that is set to LF (i.e. "files.eol": "\n");
  • .vscode/launch.json - settings for C/C++ code debugging;
  • configs/ - the folder includes config and ignore files for: ESlint, Prettier, Commitlint packages. Currently about ignore files: node_modules and a few more folders are ignored (check .gitignore file);
  • .editorconfig - the project common settings (as for now it's as in RSSchool recommended check the EditorConfig for VS Code for more.
    notice: EditorConfig IDE extension required!);
  • build/ - built binaries of the project (note: build/compile_commands.json are strongly required for linter!);
  • .gitignore - exlude node_modules and a few more folders from git watching (like dist etc, check the file for more);
  • LICENSE.txt - license file;
  • package.json - the heart of all. Check the scripts (especially, the paths for linting/prettier'ing. Currently: './src'). Scripts already have CLI prefixes to link with config and ignore files;

It's assumed that C/C++ lang tools are placed at their own folders inside C:/Tools/ and added to the PATH environment variable of Windows! Check the To add a path to the PATH environment variable for more.

Compilers usage

  • in VSCode create new PowerShell terminal (Bash won't suit, you'll get an error via compilation at Windows collect2.exe: error: ld returned 116 exit status / when using g++ with git bash and including );
  • from cwd go to the folder with your *.c or *.cpp (or C/C++ languages relative) files (e.g. cd src);
  • create helloworld.c with C code insdie (don't forget to include headers);
  • run gcc helloworld.c -o helloworld.exe;
  • run your new .exe file (e.g. ./helloworld.exe);
  • the result will be in the terminal;

Check https://code.visualstudio.com/docs/languages/cpp#_create-a-hello-world-app for more;

Also useful Создание первой программы (RU);

Another way is to use Code Runner VSCode extenion to ease the compilation and execution processes. Don't forget to check the VSCode settings (Code-runner: Executor Map) to set the extension to proper way like this:

 "code-runner.executorMap": {
    "c": "cd $dirWithoutTrailingSlash && clang --target=x86_64-w64-windows-gnu -g -std=c17 $fileName -o $fileNameWithoutExt && ./$fileNameWithoutExt",
    "cpp": "cd $dirWithoutTrailingSlash && clang++ --target=x86_64-w64-windows-gnu -g -std=c++20 $fileName -o $fileNameWithoutExt && ./$fileNameWithoutExt",
 }

or to link all the *.c or *.cpp files (glob patterns) into one main file
(@note! do not run code runner on files differ from main.(c|cpp) !
This params will work only for flat files structure!!!
otherwise link files manually with complier option -I (e.g. gcc -g -std=c17 -Iinclude *.c -o main, where include (or whatever set folders) is a folder with *.h files (means, hey, compiler, look also for *.h files in the include folder!))

 "code-runner.executorMap": {
    "c": "cd $dirWithoutTrailingSlash && clang --target=x86_64-w64-windows-gnu -g -std=c17 *.c -o $fileNameWithoutExt && ./$fileNameWithoutExt",
    "cpp": "cd $dirWithoutTrailingSlash && clang++ --target=x86_64-w64-windows-gnu -g -std=c++20 *.cpp -o $fileNameWithoutExt && ./$fileNameWithoutExt",
 }

about $fileName, $fileNameWithoutExt, $dirWithoutTrailingSlash read the Code Runner docs.

Debugging
-g flag is required for debugging (VSCode Debug C++: Why does the flow not stop at breakpoint?);

to ease the debugging process add .vscode/launch.json. the two main settings are:

  • "program" => e.g. "program": "${fileDirname}/${fileBasenameNoExtension}.exe", path to the example_file.exe for debugging
  • "miDebuggerPath" => e.g. "miDebuggerPath": "C:\\Tools\\msys64\\ucrt64\\bin\\gdb.exe",, path to the debugger (currently it's a gdb).

${fileDirname}, ${fileBasenameNoExtension} here are VSCode variables. Learn about them (note: extremely usefull tool!) via Variables reference with examples (VSCode);


note!
clang and clang++ compilers won't work standalone!!! They're strongly required libs!!!, so that's why flag --target=x86_64-w64-windows-gnu is must be nested (for actual Windows especially)! Otherwise one'll have got the compilation error like this:

$ clang -std=c17 ./task.c -o task,exe
clang: warning: unable to find a Visual Studio installation; try running Clang from a developer command prompt [-Wmsvc-not-found]
task.c:2:10: fatal error: 'stdio.h' file not found
    2 | #include <stdio.h>
      |          ^~~~~~~~~
1 error generated.

check the using Clang in windows 10 for C/C++ for more.

Linters, Formatters

it's required to be installed at your PC (and added to the PATH environment variable of Windows) / in VSCode :

then add following lines to the ./.vscode/settings.json

...
 "[c]": {
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd"
  },
  "[cpp]": {
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd"
  },
  "clangd.path": "C:\\Tools\\LLVM\\bin\\clangd.exe", // path to Clangd, required
  "clangd.arguments": [
    "--log=verbose",  // logs of extension work
    "--pretty", // logs formatting
    "--background-index", // for indexing files
    "--clang-tidy", // use clang-tidy in real time
    "--header-insertion=iwyu", // include headers automatically (or set 'never')
    "--completion-style=detailed",  // autocomplete
    "--enable-config" // required for .clangd config usage
  ],
  "C_Cpp.intelliSenseEngine": "disabled", // disable C/C++
  //  extension intelliSense because we're using the clangd extension.
  // Clangd conflicts with C/C++. Clangd is able "on fly" to show errors.

build/compile_commands.json are strongly required for linter proper work! if they don't exist build binaries via Cmake + Ninja with

# enable build/compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

in the ./CMakeLists.txt.

note: Check the paths to msys64 folder (e.g. C/Tools/msys64/ucrt64)! clang-tidy is a Linter for C and C++;


note
for technical reasons, .clang-format, .clang-tidy, .clangd configs work only from the root of the project. Do not nest them to the ./configs/... (untidy, don't like that kind).


  • ./.clang-format - contains rules for formatting the C and C++ files' code. Feel free to change it as your wish (currently it's a custom K&R style, based on LLVM style, but with IndentWidth: 2 instead of IndentWidth: 4).
  • ./.clang-tidy - config for code lintering (Clang-Tidy docs. Currently set particularly to Mozilla checks with AirBnB style param naming).
  • ./.clangd - config for Clangd VSCode extenion (clangd teach your editor C++) and don't forget about it's settings in the ./.vscode/settings.json.

Clangd works only with clang, clang++ compilers (with --target=x86_64-w64-windows-gnu), no other way. Check the settings and params at ./.clangd and via official docs. Also check in the clangd settings: Clangd: Path => path to the clangd.exe (e.g. C:\\Tools\\LLVM\\bin\\clangd.exe) and don't forget to update the extension's databases (or enable Clangd: Check Updates in the Clangd extension settings).

Execa usage:

Execa is a powerful tool for NodeJS based projects. it gives possibility to create CI/CD processes and to automate routine actions (like updating and regression testing of the boilerplate / project).

To install Execa run (as devDependencies)

npm i -D execa

Check the configs/execa/main.js script for details (it update's the boilerplate's packages and create configs/execa/update-error.log with result of the process).

for ease of use add the command to the package.json/scripts:

"scripts": {
    "update:packages": "node ./configs/execa/main.js"
  },

suggestion:
one can automate process even more by creating script that update and run regression tesing of all the projects / boilerplates.

e.g. the directory of all projects / boilerplates is E:/Code learning. Then create script, let's name it update_all_packages.mjs with this logic (pay attention: E:/Code learning doesn't contain any npm packages! update_all_packages.mjs just imports Execa from the closest existing repo to prevent catalog pollution and bloating!):

E:/Code learning/update_all_packages.mjs example (click to view)
import {
  execaNode,
  ExecaError,
} from './boilerplate-eslint-prettier-husky/node_modules/execa/index.js';
import fs from 'fs/promises';
import path from 'path';

/**
 * Write log file with date and `No errors logged.` inner.
 * If `update-error.log` doesn't exist one will be created beside the script
 *
 * @param {string} pathToLogFile - path (absolute is prefered) to the log file
 * @param {string} logMessage - log message for writing into the log file
 *
 * @returns {Promise<void>}
 * @throws Error writing log: ${error.message}
 */
async function writeSuccessLogFile(pathToLogFile, logMessage) {
  try {
    // write logfile beside the script
    await fs.appendFile(
      pathToLogFile,
      `[${new Date().toLocaleString()}]\n No errors logged.\n\n${logMessage}`,
    );
    console.log(`Log has been written to the ${pathToLogFile}`);
  } catch (error) {
    console.error(`Error writing log: ${error.message}`);
  }
}

/**
 * Write log file with date and error message inside.
 * If `update-error.log` doesn't exist one will be created beside the script
 *
 * @param {string} pathToLogFile - path (absolute is prefered) to the log file
 * @param {Error | ExecaError} error - object Error
 *
 * @returns {Promise<void>}
 * @throws Error writing log: ${error.message}
 */
async function writeErrorLogFile(pathToLogFile, error) {
  try {
    // write logfile beside the script
    await fs.appendFile(
      pathToLogFile,
      `[${new Date().toLocaleString()}] ${error.message}${
        (error instanceof ExecaError ? error.stderr : error) ??
        'No stderr available.'
      }\n`,
    );
    console.log(`Log has been written to the ${pathToLogFile}`);
  } catch (error) {
    console.error(`Error writing log: ${error.message}`);
  }
}

/**
 * Execute NodeJS command `node path/to/script.js` for every path in the {@link array}.
 * P.S. independantly to OS.
 *
 * @param {string[]} array - array of paths (strings)
 *    to boilerplate's / project ' s `configs/execa/main(js|ts)`
 * @returns {Promise<string[]>}
 * @throws ExecaError occur: ${error.message} - if error was thrown from the Execa
 * @throws ${error.message} - if error happend in another one case
 */
async function runNodeScript(array) {
  /** @type {string[]} */
  const arrOfLogs = [];

  for (const pathToScript of array) {
    /** @type {string} */
    const pathToScriptNormalized = path.resolve(pathToScript);
    // configs/execa/main.(j|t)s is a folder with execa script (JavaScript or TypeScript one)
    // this sctructure is the same (and must be the same!) in every project / boilerplate
    /** @type {string} */
    const currentScriptCWD = pathToScript.replace(
      /\/configs\/execa\/main\.(j|t)s$/gi,
      '',
    );
    // use `cwd` option to prevent paths problems!!!
    try {
      /**
       * @type {import("./boilerplate-eslint-prettier-husky/node_modules/execa/index.d.ts").Result}
       * @example
       *    string like this:
       *    'start checking for outdated packages...
       *    All packages are up-to-date. Skipping npm update.
       *    Log has been written to the
       *      E:\Code learning\integration-playground__webpack-react-ts\configs\execa\update-error.log'
       */
      const { stdout } = await execaNode(pathToScriptNormalized, {
        cwd: currentScriptCWD,
        verbose: 'full',
        cleanup: true,
      });

      arrOfLogs.push(stdout ?? 'empty stdout');

      console.log(`${currentScriptCWD}: successfully executed!`);
    } catch (error) {
      if (error instanceof ExecaError) {
        console.error(`ExecaError occur: ${error.message}`);
      } else {
        console.error(error.message);
      }
    }
  }

  return arrOfLogs;
}

/**
 * Update the project's | bolerplate's packages and run commands / tests
 * for regression testing and compatibility. If errors occur check the `update-projects-packages.log`
 * or `update-error.log` in the boilerplate's / project's configs/execa/update-error.log
 *
 * @returns {Promise<void>}
 * @throws An error occured: ${error.message}
 */
async function main() {
  const currentDir = path.resolve();

  const logFile = path.resolve(currentDir, `./update-projects-packages.log`);

  /** @type {string[]} */
  const arrOfScriptpaths = [
    './integration-playground__webpack-react-ts/configs/execa/main.js',
    './integration-playground__webpack-react-js/configs/execa/main.js',
    './boilerplate-webpack-gulp-html-scss-ts-components/configs/execa/main.js',
    './boilerplate-webpack-gulp-html-scss-js-components/configs/execa/main.js',
    './design-patterns/configs/execa/main.js',
    './boilerplate-codewars/configs/execa/main.js',
    './boilerplate-eslint-prettier-husky/configs/execa/main.js',
    './boilerplate-jest/configs/execa/main.js',
    './boilerplate-webpack-react-js/configs/execa/main.js',
    './boilerplate-webpack-react-ts/configs/execa/main.js',
    './rs_school/rsschool-cv/configs/execa/main.js',
    './youtube-dl_utility/configs/execa/main.js',
  ];

  // clean up the log file
  await fs.writeFile(logFile, '');

  console.log(`start running updating scripts...`);

  try {
    /** @type {string[]} */
    const logMessage = await runNodeScript(arrOfScriptpaths);

    // write logfile beside the script
    await writeSuccessLogFile(logFile, logMessage.join('\n\n'));
  } catch (error) {
    console.error(`An error occured: ${error.message}`);

    // write logfile beside the script
    await writeErrorLogFile(logFile, error);
  }
}

main();

then just run node update_all_packages.mjs from the E:/Code learning and check logs in the terminal and E:/Code learning/update-projects-packages.log for details.


Execa contains all the necessary types annotations and it's scripts can be written in TypeScript (Execa and TypeScript). In a next coming releases of NodeJS that will support TypeScript as native one it will be pretty sweet for usage)

Integration with Connections links:

To integrate the boilerplate do the following steps (note: copy the project structure as is!!!):
@note all the next pathes are cwd relative.
It's assumed that LLVM (with clang-tidy and clang-format) is installed in your system and added to the path environment => C:/Tools/LLVM/bin and compilers are installed:

  • clang, clang++ (and path environment => C:/Tools/LLVM/bin) (must have for clangd real time linter, won't work otherwise) and gcc, g++, gdb (and path environment => C:/Tools/msys64/ucrt64/bin)

  • copy:
    .clang-format
    .clang-tidy
    .clangd
    .editorconfig
    .gitignore
    build
    .vscode

  • check out files and pathes to the compilers / debuggers to suit your system and folders layout!!!
    (currently => C:/Tools/):
    .vscode/c_cpp_properties.json:

    • configurations...{intelliSenseMode...}, configurations...{compilerPath...}, configurations...{compileCommands...}, configurations...{cStandard...}, configurations...{cppStandard...}

    .vscode/settings.json:

    • "[c]", "[cpp]", "clangd.path", "clangd.arguments", "C_Cpp.default.compilerPath"

    .vscode/launch.json:

    • "configurations"...{ "miDebuggerPath" }

    use clangd and Doxygen Documentation Generator extensions for VSCode.

    optionally (TS/JS linting / formatting, Husky for commit messages checking (to suit to git - flow)):
    @note all the next pathes are cwd relative.

    copy:

    • configs, .husky

    install the npm packages:

    npm i -D @commitlint/cli @commitlint/config-conventional eslint-config-airbnb-base eslint-config-prettier eslint eslint-plugin-import execa husky prettier

copy from .vscode/settings.json all the data till "[c]"... use format-code-action extension for VSCode (real - time linting and formatting on save).

With the new packages releases, the ones above can turn to pumpkin, so check'em out with official docs!!!

Links:

C/C++ tutorials:

C/C++ compilers:

LLVM, Linters, Formatters:

VSCode usage' links:

ESLint:

Prettier:

Husky:

Execa:

Connections:

done: July 03, 2025

About

It's an boilerplate for usage of c/c++ compilers, linters, formatters (the settings) in a future project. Check out the docs below to be in actual tune!

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published