VS Code — Compile Multiple C/C++ Files in One Directory
This post covers how to compile multiple C/C++ source files that live in the same directory using a single VS Code build task — no Makefile required.
Environment: Visual Studio Code (any recent version), gcc / g++ installed and on PATH
[01] The Problem — Single-File vs. Multi-File Compilation
By default, VS Code’s C/C++ quick-build shortcuts compile only the currently open file (${file}). When a project is split across several .cpp or .c files in one directory, that produces linker errors because the other translation units are never passed to the compiler.
Example — two-file project:
1
2
3
project/
├── main.cpp ← entry point, calls helper()
└── helper.cpp ← defines helper()
Compiling only main.cpp fails:
1
2
/tmp/ccXXXX.o: undefined reference to `helper()'
collect2: error: ld returned 1 exit status
The fix is to pass project/*.cpp to the compiler — and VS Code’s Variables Reference makes this easy to express without hard-coding the path.
[02] Variables Reference
VS Code exposes a set of predefined variables that can be used inside tasks.json, launch.json, and settings.json. The two variables used in this recipe are:
| Variable | Expands to |
|---|---|
${fileDirname} |
Absolute path of the directory containing the currently open file |
${fileExtname} |
Extension of the currently open file (e.g., .cpp) |
${file} |
Absolute path of the currently open file |
${fileBasenameNoExtension} |
Filename without path or extension — used as the output binary name |
${workspaceRoot} |
Absolute path of the workspace root folder |
Combining the first two: "${fileDirname}/*${fileExtname}" expands to something like /home/user/project/*.cpp — exactly what the compiler needs.
Full variable list: VS Code Variables Reference
[03] Writing tasks.json
Place tasks.json inside .vscode/ at your workspace root. The file below defines three build tasks and one run task.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
{
"version": "2.0.0",
"runner": "terminal",
"type": "shell",
"echoCommand": true,
"presentation": { "reveal": "always" },
"tasks": [
{
"label": "save_and_compile_for_C++-groups",
"command": "g++",
"args": [
"${fileDirname}/*${fileExtname}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"group": "build",
"problemMatcher": {
"fileLocation": ["relative", "${workspaceRoot}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"label": "save_and_compile_for_C++-single",
"command": "g++",
"args": [
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"group": "build",
"problemMatcher": {
"fileLocation": ["relative", "${workspaceRoot}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"label": "save_and_compile_for_C",
"command": "gcc",
"args": [
"${file}",
"-g",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"group": "build",
"problemMatcher": {
"fileLocation": ["relative", "${workspaceRoot}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"label": "execute",
"command": "cmd",
"group": "test",
"args": [
"/C", "${fileDirname}\\${fileBasenameNoExtension}"
]
}
]
}
[04] Task Breakdown
| Task label | Compiler | Input files | Use case |
|---|---|---|---|
save_and_compile_for_C++-groups |
g++ |
All *.cpp in current dir |
Multi-file C++ project |
save_and_compile_for_C++-single |
g++ |
Current file only | Single-file C++ sketch |
save_and_compile_for_C |
gcc |
Current file only | Single-file C program |
execute |
cmd /C |
Compiled binary | Run the output on Windows |
Key argument — groups task:
1
"${fileDirname}/*${fileExtname}"
This glob expands at shell evaluation time to every file matching the extension of the open file inside its directory. If you have main.cpp open, VS Code sends /absolute/path/to/project/*.cpp to g++.
[05] Running the Build Task
- Open any
.cppfile in the target directory. - Press
Ctrl+Shift+B(orCmd+Shift+Bon macOS) to open the build task picker. - Select save_and_compile_for_C++-groups to compile all files in the directory.
- Check the Terminal panel for compiler output and errors.
To set one task as the default build (Ctrl+Shift+B runs it directly without a picker), add "group": { "kind": "build", "isDefault": true } to that task’s group field.
[06] Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
g++: command not found |
g++ not on PATH |
Install build-essential (Linux) or MinGW (Windows) |
| Glob not expanding | Shell does not support glob | Use "type": "shell" and wrap the arg in quotes |
| Only one file compiled | Wrong task selected | Pick the -groups task, not -single
|
| Binary not found after compile | Output path mismatch | Check ${fileDirname}/${fileBasenameNoExtension} resolves correctly in the terminal |