C++ Compiling with Visual C++ (Command Line)


For programmers coming from GCC or Clang to Visual Studio, or programmers more comfortable with the command line in general, you can use the Visual C++ compiler from the command line as well as the IDE.

If you desire to compile your code from the command line in Visual Studio, you first need to set up the command line environment. This can be done either by opening the Visual Studio Command Prompt/Developer Command Prompt/x86 Native Tools Command Prompt/x64 Native Tools Command Prompt or similar (as provided by your version of Visual Studio), or at the command prompt, by navigating to the VC subdirectory of the compiler's install directory (typically \Program Files (x86)\Microsoft Visual Studio x\VC, where x is the version number (such as 10.0 for 2010, or 14.0 for 2015) and running the VCVARSALL batch file with a command-line parameter specified here.

Note that unlike GCC, Visual Studio doesn't provide a front-end for the linker (link.exe) via the compiler (cl.exe), but instead provides the linker as a separate program, which the compiler calls as it exits. cl.exe and link.exe can be used separately with different files and options, or cl can be told to pass files and options to link if both tasks are done together. Any linking options specified to cl will be translated into options for link, and any files not processed by cl will be passed directly to link. As this is mainly a simple guide to compiling with the Visual Studio command line, arguments for link will not be described at this time; if you need a list, see here.

Note that arguments to cl are case-sensitive, while arguments to link are not.

[Be advised that some of the following examples use the Windows shell "current directory" variable, %cd%, when specifying absolute path names. For anyone unfamiliar with this variable, it expands to the current working directory. From the command line, it will be the directory you were in when you ran cl, and is specified in the command prompt by default (if your command prompt is C:\src>, for example, then %cd% is C:\src\).]

Assuming a single source file named main.cpp in the current folder, the command to compile and link an unoptimised executable (useful for initial development and debugging) is (use either of the following):

cl main.cpp
// Generates object file "main.obj".
// Performs linking with "main.obj".
// Generates executable "main.exe".

cl /Od main.cpp
// Same as above.
// "/Od" is the "Optimisation: disabled" option, and is the default when no /O is specified.

Assuming an additional source file "niam.cpp" in the same directory, use the following:

cl main.cpp niam.cpp
// Generates object files "main.obj" and "niam.obj".
// Performs linking with "main.obj" and "niam.obj".
// Generates executable "main.exe".

You can also use wildcards, as one would expect:

cl main.cpp src\*.cpp
// Generates object file "main.obj", plus one object file for each ".cpp" file in folder
//  "%cd%\src".
// Performs linking with "main.obj", and every additional object file generated.
// All object files will be in the current folder.
// Generates executable "main.exe".

To rename or relocate the executable, use one of the following:

cl /o name main.cpp
// Generates executable named "name.exe".

cl /o folder\ main.cpp
// Generates executable named "main.exe", in folder "%cd%\folder".

cl /o folder\name main.cpp
// Generates executable named "name.exe", in folder "%cd%\folder".

cl /Fename main.cpp
// Same as "/o name".

cl /Fefolder\ main.cpp
// Same as "/o folder\".

cl /Fefolder\name main.cpp
// Same as "/o folder\name".

Both /o and /Fe pass their parameter (let's call it o-param) to link as /OUT:o-param, appending the appropriate extension (generally .exe or .dll) to "name" o-params as necessary. While both /o and /Fe are to my knowledge identical in functionality, the latter is preferred for Visual Studio. /o is marked as deprecated, and appears to mainly be provided for programmers more familiar with GCC or Clang.

Note that while the space between /o and the specified folder and/or name is optional, there cannot be a space between /Fe and the specified folder and/or name.

Similarly, to produce an optimised executable (for use in production), use:

cl /O1 main.cpp
// Optimise for executable size.  Produces small programs, at the possible expense of slower
//  execution.

cl /O2 main.cpp
// Optimise for execution speed.  Produces fast programs, at the possible expense of larger
//  file size.

cl /GL main.cpp other.cpp
// Generates special object files used for whole-program optimisation, which allows CL to
//  take every module (translation unit) into consideration during optimisation.
// Passes the option "/LTCG" (Link-Time Code Generation) to LINK, telling it to call CL during
//  the linking phase to perform additional optimisations.  If linking is not performed at this
//  time, the generated object files should be linked with "/LTCG".
// Can be used with other CL optimisation options.

Finally, to produce a platform-specific optimized executable (for use in production on the machine with the specified architecture), choose the appropriate command prompt or VCVARSALL parameter for the target platform. link should detect the desired platform from the object files; if not, use the /MACHINE option to explicitly specify the target platform.

// If compiling for x64, and LINK doesn't automatically detect target platform:
cl main.cpp /link /machine:X64

Any of the above will produce an executable with the name specified by /o or /Fe, or if neither is provided, with a name identical to the first source or object file specified to the compiler.

cl a.cpp b.cpp c.cpp
// Generates "a.exe".

cl d.obj a.cpp q.cpp
// Generates "d.exe".

cl y.lib n.cpp o.obj
// Generates "n.exe".

cl /o yo zp.obj pz.cpp
// Generates "yo.exe".

To compile a file(s) without linking, use:

cl /c main.cpp
// Generates object file "main.obj".

This tells cl to exit without calling link, and produces an object file, which can later be linked with other files to produce a binary.

cl main.obj niam.cpp
// Generates object file "niam.obj".
// Performs linking with "main.obj" and "niam.obj".
// Generates executable "main.exe".

link main.obj niam.obj
// Performs linking with "main.obj" and "niam.obj".
// Generates executable "main.exe".

There are other valuable command line parameters as well, which it would be very useful for users to know:

cl /EHsc main.cpp
// "/EHsc" specifies that only standard C++ ("synchronous") exceptions will be caught,
//  and `extern "C"` functions will not throw exceptions.
// This is recommended when writing portable, platform-independent code.

cl /clr main.cpp
// "/clr" specifies that the code should be compiled to use the common language runtime,
//  the .NET Framework's virtual machine.
// Enables the use of Microsoft's C++/CLI language in addition to standard ("native") C++,
//  and creates an executable that requires .NET to run.

cl /Za main.cpp
// "/Za" specifies that Microsoft extensions should be disabled, and code should be
//  compiled strictly according to ISO C++ specifications.
// This is recommended for guaranteeing portability.

cl /Zi main.cpp
// "/Zi" generates a program database (PDB) file for use when debugging a program, without
//  affecting optimisation specifications, and passes the option "/DEBUG" to LINK.

cl /LD dll.cpp
// "/LD" tells CL to configure LINK to generate a DLL instead of an executable.
// LINK will output a DLL, in addition to an LIB and EXP file for use when linking.
// To use the DLL in other programs, pass its associated LIB to CL or LINK when compiling those
//  programs.

cl main.cpp /link /LINKER_OPTION
// "/link" passes everything following it directly to LINK, without parsing it in any way.
// Replace "/LINKER_OPTION" with any desired LINK option(s).

For anyone more familiar with *nix systems and/or GCC/Clang, cl, link, and other Visual Studio command line tools can accept parameters specified with a hyphen (such as -c) instead of a slash (such as /c). Additionally, Windows recognises either a slash or a backslash as a valid path separator, so *nix-style paths can be used as well. This makes it easy to convert simple compiler command lines from g++ or clang++ to cl, or vice versa, with minimal changes.

g++ -o app src/main.cpp
cl  -o app src/main.cpp

Of course, when porting command lines that use more complex g++ or clang++ options, you need to look up equivalent commands in the applicable compiler documentations and/or on resource sites, but this makes it easier to get things started with minimal time spent learning about new compilers.

In case you need specific language features for your code, a specific release of MSVC was required. From Visual C++ 2015 Update 3 on it is possible to choose the version of the standard to compile with via the /std flag. Possible values are /std:c++14 and /std:c++latest (/std:c++17 will follow soon).

Note: In older versions of this compiler, specific feature flags were available however this was mostly used for previews of new features.