SimplifyC++ Article
Building C++ Projects with MSVC Without Build Systems
Building C++ Projects with MSVC Without Build Systems
Microsoft Visual C++ (MSVC) is a powerful compiler that integrates with Visual Studio but can also be used independently via the Developer Command Prompt or PowerShell. While most large C++ projects use CMake or MSBuild, it is entirely possible to build and manage projects manually using MSVC’s cl.exe compiler.
This guide walks through using MSVC to compile small and large C++ projects, link libraries, enable C++20, C++23, and C++26, optimize builds, and automate the process with scripts.
Setting Up MSVC Command Line
Before compiling, ensure you have MSVC installed.
Open the Developer Command Prompt
To use MSVC’s compiler (cl.exe), open:
x64 Native Tools Command Prompt for VS
x86 Native Tools Command Prompt for VS (for 32-bit builds)
Alternatively, run this in PowerShell:
& "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat"
This sets up the correct environment variables for cl.exe.
Compiling a Single C++ File
For a basic program:
cl main.cpp
This produces main.exe.
Enabling a Specific C++ Standard (C++20, C++23, C++26)
MSVC defaults to C++14. Use /std:c++20 or newer for modern C++ features:
cl /std:c++20 main.cppcl /std:c++23 main.cppcl /std:c++latest main.cpp # Experimental C++26 (C++2b)
C++23 Features in MSVC:
std::expectedfor error handling.std::mdspanfor multi-dimensional views.std::printfor modern-style printing.
C++26 Features (Experimental)
Deduction in
thispointer.Pattern Matching (if approved).
Compiling Multiple Files
For larger projects with multiple source files (main.cpp and helper.cpp):
cl main.cpp helper.cpp /Fe:my_program.exe
This compiles and links both files.
Using Object Files (.obj) for Incremental Compilation
Instead of recompiling everything:
cl /c main.cpp helper.cppcl main.obj helper.obj /Fe:my_program.exe
/c→ Only compiles to.obj(no linking)./Fe:output.exe→ Sets the executable name.
Managing Large Projects Without Build Systems
For large projects, organize files properly:
my_project/├── src/│ ├── main.cpp│ ├── helper.cpp│ ├── module/│ │ ├── math.cpp│ │ ├── physics.cpp├── include/│ ├── helper.hpp│ ├── module/│ │ ├── math.hpp│ │ ├── physics.hpp├── build/
Compiling with Include Paths (/I)
If header files are in include/:
cl /Iinclude src\main.cpp src\helper.cpp /Fe:my_program.exe
Compiling with Object Files
For efficiency, compile separately:
cl /c /Iinclude src\main.cpp /Fo:build\main.objcl /c /Iinclude src\helper.cpp /Fo:build\helper.objcl /c /Iinclude src\module\math.cpp /Fo:build\math.objcl build\main.obj build\helper.obj build\math.obj /Fe:my_program.exe
Linking Libraries in MSVC
Linking Standard Libraries (Math, Threads)
cl main.cpp /link /NODEFAULTLIB:LIBCMT /DEFAULTLIB:msvcrt.lib
Linking a Static Library (.lib)
cl main.cpp mylib.lib /Fe:my_program.exe
Linking a Dynamic Library (.dll)
First, ensure you have mylib.lib and mylib.dll, then:
cl main.cpp mylib.lib /Fe:my_program.exe
Place mylib.dll in the same folder as my_program.exe for runtime linking.
Enabling Optimizations and Debugging
Optimization Levels
/O1→ Optimize for size./O2→ Optimize for speed./Ox→ Maximum optimizations./GL→ Whole-program optimization.
Example:
cl /O2 main.cpp /Fe:optimized.exe
Debugging with /Zi and /FS
/Zi→ Debugging symbols./FS→ Multi-threaded compilation./Od→ Disable optimizations for debugging.
Example:
cl /Zi /Od main.cpp /Fe:debug.exe
Cross-Compiling with MSVC
Compiling for 32-bit Windows
cl /EHsc /DWIN32 main.cpp /Fe:my_program32.exe
Compiling for 64-bit Windows
cl /EHsc /DWIN64 main.cpp /Fe:my_program64.exe
Targeting ARM64 (Windows on ARM)
cl /D_ARM64 main.cpp /Fe:my_program_arm64.exe
Automating Builds with a Batch Script**
Instead of manually compiling files, use a batch file (build.bat):
Example: build.bat
@echo offmkdir buildcl /c /Iinclude src\main.cpp /Fo:build\main.objcl /c /Iinclude src\helper.cpp /Fo:build\helper.objcl /c /Iinclude src\module\math.cpp /Fo:build\math.objcl build\main.obj build\helper.obj build\math.obj /Fe:my_program.exeecho Build complete!
Run it:
build.bat
When to Use a Build System (CMake/MSBuild)
While manual builds work for many projects, a build system becomes necessary for:
Cross-platform support.
Dependency management.
Automating complex builds.
However, understanding MSVC without CMake is crucial for:
Debugging build errors.
Creating simple builds.
Learning how compilers work internally.
Conclusion
MSVC provides powerful tools to build C++ programs without relying on CMake or MSBuild. By using cl.exe, you can:
Compile simple and large projects manually.
Optimize builds for performance.
Link external libraries (
.liband.dll).Automate builds with batch scripts.
This method is useful for learning, debugging, and small projects, but for large applications, CMake or MSBuild is recommended.