Comment j'utilise VSCode pour les projets C
Cet article décrit comment j’utilise Visual Studio Code (VSCode) pour de petits projets C, sans bibliothèques externes, pour écrire, compiler, déboguer et organiser des projets C.
Ce tutoriel est orienté pour une utilisation avec VSCode mais fonctionnerait sans installer d’extension dans QtCreator ou CLion (je suppose, je ne les ai pas utilisés depuis plusieurs années) ou avec neovim/vim/emacs avec les bonnes extensions. Je ne sais pas si toutes les extensions sont disponibles dans VSCodium.
Si vous avez des suggestions, n’hésitez pas à me les faire savoir.
traduit automatiquement de la version anglaise
Sommaire
- Sommaire
- Outils et Configuration
- Structure du Projet
- Construction et Exécution du Projet
- Makefile
- Linter
- Formattage
Outils et Configuration
Pour travailler avec C/C++ dans VSCode, j’utilise les extensions suivantes :
- C/C++ Extension Pack
IntelliSense, débogage, tâches de compilation, …
- Clang-Format
Pour le formatage automatique du code.
Autres outils à installer :
- GCC pour la compilation (cela fonctionne aussi avec Clang)
- CMake pour gérer le projet.
- clang-format comme formateur
- clang-tidy comme linter
- cppcheck comme linter
Sur Linux et macOS, cela devrait être facile à installer. Sur Windows, je recommande d’installer WSL (Windows Subsystem for Linux) pour obtenir un environnement Linux complet à utiliser dans VSCode.
Structure du Projet
Le projet exemple (disponible ici) est organisé comme suit :
my_c_project/
├── build/
├── .clang-format
├── .clang-tidy
├── CMakeLists.txt
├── Makefile
└── src/
├── main.c
├── utils.c
└── utils.h
Oui, mes fichiers .c et .h sont dans le même répertoire, les fichiers .h pourraient également aller dans un répertoire include
.
Pour ouvrir my_c_project
dans VSCode, vous pouvez utiliser :
# décompresser l'archive
unzip my_c_project.zip
# aller dans le répertoire
cd my_c_project
# ouvrir avec VSCode
code .
ou faites un clic droit sur le dossier my_c_project
et “Ouvrir avec code”, si disponible, ou “Ouvrir avec une autre application” puis “VSCode”.
Vous devez ouvrir my_c_project
dans votre éditeur de code, pas le dossier src
.
Exemple de Fichiers Source (avec bugs)
Voici un exemple avec des bugs pour montrer les problèmes à la compilation et à l’exécution :
src/main.c
#include <stdio.h>
#include <stdlib.h>
#include "utils.h"
int main(int argc, [[maybe_unused]] char *argv[argc + 1]) {
printf("Hello!\n");
int a = 5;
int b = 6;
int result = add(a, b);
printf("%d + %d = %d\n", a, b, result);
int *ptr = malloc(sizeof(int) * 10);
// Buffer overflow: index 10 is out of bounds (0-9)
// Sanitizer will detect it at runtime in debug mode
ptr[10] = 42;
// Memory leak: ptr is not freed
return EXIT_SUCCESS;
}
src/utils.h
#ifndef UTILS_H
#define UTILS_H
int add(int a, int b);
#endif // UTILS_H
src/utils.c
#include "utils.h"
int add(int a, int b) {
return a + b;
}
Construction et Exécution du Projet
CMake sera responsable de la construction du projet.
Voici le fichier CMakeLists.txt
qui construira tout pour nous :
CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(my_c_project LANGUAGES C)
# List all sources files
set(PROJECT_SOURCE_FILES
${CMAKE_SOURCE_DIR}/src/main.c
${CMAKE_SOURCE_DIR}/src/utils.c
)
# Use clang-tidy if available, you may need to edit this with the correct version of clang-tidy
find_program(CLANG_TIDY_EXE NAMES "clang-tidy-19" "clang-tidy")
if(CLANG_TIDY_EXE)
message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXE}")
set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY_EXE}")
endif()
# Use modern C
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Default to Release if not specified
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif()
# Detect compiler
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(COMPILER_IS_CLANG TRUE)
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU")
set(COMPILER_IS_GCC TRUE)
endif()
# Enable LTO in Release mode
if(CMAKE_BUILD_TYPE MATCHES Release)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
if(COMPILER_IS_GCC)
set(CMAKE_AR "gcc-ar")
set(CMAKE_RANLIB "gcc-ranlib")
endif()
endif()
# Base warning flags
set(WARN_FLAGS_COMMON
-Wall
-Wextra
-Wshadow
-Wcast-align
-Wunused
-Wpedantic
-Wconversion
-Wmisleading-indentation
-Wnull-dereference
-Wdouble-promotion
-Wformat=2
-Werror
)
add_executable(${PROJECT_NAME} ${PROJECT_SOURCE_FILES})
# Apply flags per configuration with conditional logic
target_compile_options(${PROJECT_NAME} PRIVATE
# Common flags
$<$<CONFIG:Debug>:${WARN_FLAGS_COMMON} -O0 -g -DDEBUG -fsanitize=address,undefined -fno-sanitize-recover=all>
$<$<CONFIG:Release>:${WARN_FLAGS_COMMON} -O3 -DNDEBUG -flto=auto -s>
)
# Link sanitizers too for debug mode
target_link_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Debug>:-fsanitize=address,undefined -fno-sanitize-recover=all>
)
Pour résumer le contenu du CMakeLists.txt
:
- définir la version de cmake
- puis nous donnons un nom au projet, ici my_c_project, ce sera le nom de l’exécutable dans le répertoire build
-
la section suivante doit être mise à jour à mesure que votre projet grandit :
# List all sources files set(PROJECT_SOURCE_FILES ${CMAKE_SOURCE_DIR}/src/main.c ${CMAKE_SOURCE_DIR}/src/utils.c )
ajoutez vos futurs fichiers ici
find_program(CLANG_TIDY_EXE NAMES "clang-tidy-19" "clang-tidy")
recherchera clang-tidy sur votre système, vous devrez peut-être modifier la ligne pour utiliser la bonne version (clang-tidy-20
par exemple).- puis nous spécifions la version de C à utiliser, ici C23
- si aucun type de build n’est donné, nous utilisons Release par défaut. L’extension CMake de VSCode définit explicitement le type de build, donc ce défaut ne s’applique que lorsque CMake est exécuté manuellement (avec
-DCMAKE_BUILD_TYPE=Debug
ouRelease
). - Ensuite, il sélectionne quel compilateur est utilisé (voir
[Scan for kit]
dans la section suivante) ou lors d’une exécution manuelle avec-DCMAKE_C_COMPILER=clang
/gcc
ouCC=clang CFLAGS=... cmake -B build -DCMAKE_BUILD_TYPE=Debug
/CC=gcc cmake -B build -DCMAKE_BUILD_TYPE=Debug
- si la build est en release, active LTO (Link Time Optimisation) pour améliorer les performances
- définir les drapeaux d’avertissement
- ajouter les drapeaux de compilation :
- en mode débogage : avec les sanitizers, les symboles de débogage (
-g
) et sans optimisations (-O0
) - en mode release : avec LTO et optimisations (
-O3
)
- en mode débogage : avec les sanitizers, les symboles de débogage (
Construire et Compiler
Pour compiler manuellement :
mkdir build
cd build || exit
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j
Pour compiler dans VSCode (si vous avez installé les extensions), vous devriez voir cette barre en bas de l’écran :
Si elle n’est pas là alors que vous avez un CMakeLists.txt
dans le dossier, cliquez sur ctrl+shift+p
puis tapez reload window
puis enter, ou fermez et rouvrez VSCode dans le dossier, et elle devrait apparaître.
Sur la capture d’écran, après les outils croisés, vous pouvez voir [GCC 13.1.0x86_64-linux-gnu]
, il est possible que vous ayez quelque chose comme [Scan for kits]
, vous pouvez cliquer dessus pour ouvrir une fenêtre déroulante en haut de VSCode :
Si rien n’apparaît sous [Unspecified]
, cliquez sur [Scan for kits]
et si vous avez gcc
ou clang
installé sur votre système, ils devraient être listés ici, choisissez la version la plus récente de GCC, ici GCC 13...
ou Clang 19
.
Une fois qu’une option est sélectionnée, cliquez sur le bouton build
, cela construira le projet et affichera les avertissements.
Avec le code bogué que je vous ai donné, si clang-tidy
est trouvé (il doit être installé, et si le nom du paquet est clang-tidy
ou clang-tidy-VERSION
), il devrait afficher l’avertissement suivant, concernant ptr
qui n’est pas libéré :
[build] /tmp/my_c_project/src/main.c:24:5: warning: Potential leak of memory pointed to by 'ptr' [clang-analyzer-unix.Malloc]
[build] 24 | return EXIT_SUCCESS;
[build] | ^
[build] /tmp/my_c_project/src/main.c:17:16: note: Memory is allocated
[build] 17 | int *ptr = malloc(sizeof(int) * 10);
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~
[build] /tmp/my_c_project/src/main.c:24:5: note: Potential leak of memory pointed to by 'ptr'
[build] 24 | return EXIT_SUCCESS;
[build] | ^
Même avec cette erreur, le code est compilé quand même (en principe, corrigez les warning, pour l’exemple des bugs, nous les laissons).
Pour exécuter le code, vous avez 2 options à droite du bouton build
:
- l’icône d’insecte : pour lancer avec le débogueur
- l’icône “play” : pour lancer dans le terminal
Lorsque vous exécutez avec le débogueur, l’exécution s’arrêtera sur les points d’arrêt que vous pouvez définir en cliquant à gauche du numéro de ligne, les erreurs d’assertion et certaines autres erreurs.
Lorsque vous exécutez dans le terminal, l’effet sera le même que :
cd build
./my_c_project
Erreurs
Comme vous pouvez le voir dans le fichier principal, à la ligne 21, ptr
est modifié en dehors de ses limites, cela déclenchera les sanitizers et affichera une erreur :
==140758==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x604000000038 at pc 0x59b9894da3a4 bp 0x7ffdd8ae5e20 sp 0x7ffdd8ae5e10
WRITE of size 4 at 0x604000000038 thread T0
#0 0x59b9894da3a3 in main /tmp/my_c_project/src/main.c:21
#1 0x7c4557e29d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#2 0x7c4557e29e3f in __libc_start_main_impl ../csu/libc-start.c:392
#3 0x59b9894da1c4 in _start (/tmp/my_c_project/build/my_c_project+0x11c4) (BuildId: b4c1263f080d2c962e39c92f6893508348192044)
...
...
...
Lors de certaines exécutions, il peut imprimer sur la console AddressSanitizer:DEADLYSIGNAL
encore et encore, arrêtez-le simplement avec Ctrl+C
puis exécutez à nouveau, après quelques fois, il s’arrête normalement (une solution pourrait être possible, je ne l’ai pas essayée).
Makefile
J’ai ajouté un fichier makefile pour simplifier les appels à la main :
> make help
Available targets:
build - Clean and build in Debug mode
build-release - Clean and build in Release mode
clean - Remove build directory
lint - Run clang-tidy and cppcheck
format - Format source code using clang-format
run - Run the compiled binary
help - Show this help message
make build
/build-release
supprimera le dossierbuild
et compilera.make clean
supprimera le dossierbuild
.make lint
appellera clang-tidy et cppcheckmake format
appellera clang-formatmake run
exécutera le programme
Linter
Les linters, comme clang-tidy
ou cppcheck
, sont utiles pour détecter des bugs dans le code de manière statique que les erreurs de compilation ne peuvent pas trouver.
clang-tidy
est automatiquement exécuté pendant la compilation (si l’exécutable est trouvé), cppcheck
peut être appelé via la commande make lint
.
Formattage
Clang-Format est utilisé pour auto-formater le code.
Le fichier de configuration .clang-format
assure un style cohérent à travers tous les fichiers et à travers différents projets.
Dans ce projet, j’ai ajouté un fichier avec le style LLVM avec les modifications suivantes :
AllowShortEnumsOnASingleLine: true
->false
AllowShortFunctionsOnASingleLine: All
->None
AllowShortLambdasOnASingleLine: All
->None
BinPackArguments: true
->false
BinPackParameters: true
->false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
->true
IndentWidth: 2
->4
Vous pouvez formater votre code en utilisant :
clang-format -i src/*.c src/*.h
ou avec la commande make format
.
Ou automatiquement à la sauvegarde en utilisant l’extension VSCode pour clang-format.
Vous devrez peut-être vérifier le paramètre format on save
dans les paramètres et choisir clang-format
comme formateur par défaut, appuyez sur Ctrl+Shift+P
puis tapez format document with
puis sélectionnez Configure Default Formatter
puis Clang-Format
.