The obvious way to create Windows programs with C and C++ (and C#, for that matter) is to use Visual Studio. And the obvious way to do the editing and compiling is to use the IDE. Whilst the IDE simplifies many aspects of the process of creating an executable, recent versions have become so complex, learning to use them beyond the basics can be an arduous task. Moreover, relying on the built-in defaults to convert one's source code into an executable program bypasses a useful opportunity to learn about this process. Another reason I tend not to use the IDE is so that I can use my own choice of editor (Vim, in my case).
There is educational merit in breaking things down into their component parts, and controlling processes as manually as possible. So, in that spirit, this page explains the steps required to compile a program from the command line.
This page will show you how to compile your source-code into machine-code using only the command-line (AKA DOS-box, console, command-prompt). In order to keep things simple, it provides only the smallest possible set of commands to achieve this. Advanced techniques are discussed in other pages.
Alas, the compilation procedure is not straightforward (so it's not surprising people just use the defaults). It's made more complicated by the difference between a 32 bit and a 64 bit host platform (the operating system on which you're writing and compiling the program), and the target platform (the one on which the program will run).
For these tutorials, I assume you've installed Visual Studio Express 2012, and version 8.1 of the Windows Software Development Kit, and that you're working on a 64 bit version of Windows 7. I also assume that you're creating 32 bit programs (32 bit programs will usually run on 64 bit Windows, but the reverse is not true).
Compiling a program actually requires two main steps; compiling the source code, then linking the object code to create an executable program or dynamically-linked library (DLL). However, by default, the compiler program in Visual Studio (cl.exe) automatically calls the linker program (link.exe) so compiling (whether using the IDE or cl.exe at the command-prompt) can seem like a one-step process.
As mentioned, the commands given here are the least required to create a simple executable program. This means that they will probably be unable to compile anything but the most basic programs. Information on compiling more sophisticated programs is given in other tutorials; hopefully by the time you get on to those, you'll have learned enough to work out how to get it compiling.
The first thing we need to do is tell the system where it can find the compiler program (cl.exe) and its various support files. The locations of these files are as follows:
GOTCHA: Annoyingly, if you try running cl without telling the system about the Common7\IDE directory, cl will run without any error message (or any other message, for that matter), but it won't do anything. The lack of any message leaves one baffled as to what went on, so be careful about that.
Note that Visual Studio Express does not include compiler programs that are 64 bit themselves. It does, however, contain 32 bit compiler programs that generate 32 bit, or 64 bit, object code. The 32-to-32 bit compiler is in the Bin directory, whilst the 32-to-64 bit compiler is in the x86_x64 subdirectory of Bin. The &lsquot;bitness’ of the compiler program is not important for our purposes; we'll just keep everything (i.e. the host and the target) 32 bit.
The compiler needs to be able to find any header files we
#include
d in our source file. The header files for the standard C
and C++ libraries are found in the following directory:
If you're writing anything beyond the most basic programs, then you'll probably need Microsoft's Software Development Kit (SDK). We gain access to its features in our source code through its header files, which are installed in the following directories:
Now that we know where the relevant files are located, we can start writing the console commands for performing the compilation. As noted, the compiler program file is called cl.exe, so that's the first thing we need. Then we have to work out what options to give it. These are the options used for this tutorial:
extern
do not
throw C++ exceptions. A bit esoteric for a simple tutorial like this, and
the main reason for including it is to silence the warning that cl otherwise
generates about exception handlers and unwind semantics.The full list of options for cl (VS 2012) is available here.
Putting all this information together, we come up with a few commands for our compiling batch script.
The first thing is to set up the PATH environment variable:
Set PATH=C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE;C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\Bin;%PATH%
The %PATH%
at the end preserves the existing value of PATH, and
puts our compiler paths at the front to give them priority (Windows stops
searching as soon as it finds the first instance of the command name).
Now, given all the paths and arguments, the command line can become extremely long and unwieldy. To make the command shorter and more readable, we can break it down with environment variables. For instance, we can store the include paths in environment variables, thus:
set INC_VS=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\Include
set INC_SDK_SH=C:\Program Files (x86)\Windows Kits\8.1\Include\shared
set INC_SDK_UM=C:\Program Files (x86)\Windows Kits\8.1\Include\um
We can now write our compiler command thus:
cl.exe /c /W4 /nologo /EHsc /I %INC_VS% /I %INC_SDK_SH% /I %INC_SDK_UM% prog.c
Just as the compiler needed to be able to find the header files, the linker needs to be able to find the library files for those headers. Note that one library (.lib) file might contain the code for more than one header file. Another important thing to note is that the library files must be compatible in terms of their bit-width (i.e. whether they contain 32 bit or 64 bit code). Also, in some cases, the library file might contain only statically or dynamically linked code. As with the header-file directories for the compiler, the library directories for the linker can be stored in environment variables:
set LIB_VS=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\Lib
set LIB_SDK=C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86
Note that there is no directory called share for the library files (at least not on my systems).
When run in compilation-only mode, cl produces an object (.obj) file, which contains the unlinked machine code. In order to link it and create the final executable program (presumably a .exe file, but it could be a .dll file), we run the link.exe program. It's arguments are thus:
#include
files.So, the command for linking is as follows:
link.exe /SUBSYSTEM:CONSOLE /LIBPATH:%LIB_VS% /LIBPATH:%LIB_SDK% prog.obj
I explicitly used the /SUBSYSTEM option here for the sake of clarity. However, it is not strictly necessary to do so because the linker can generally work out automatically which type of executable to produce from the input file. link can also work out the bitness.
Note that, unlike the cl command, which does not need the included files to be mentioned in its command line, the linker does need to be told about any object (but not library) files that it might need.
Putting all this information together, we can write a batch file that performs all the required commands, thus:
Set PATH=C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE;C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\Bin;%PATH%
set INC_VS=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\Include
set INC_SDK_SH=C:\Program Files (x86)\Windows Kits\8.1\Include\shared
set INC_SDK_UM=C:\Program Files (x86)\Windows Kits\8.1\Include\um
cl.exe /c /W4 /nologo /EHsc /I %INC_VS% /I %INC_SDK_SH% /I %INC_SDK_UM% prog.c
set LIB_VS=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\Lib
set LIB_SDK=C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86
link.exe /SUBSYSTEM:CONSOLE /LIBPATH:%LIB_VS% /LIBPATH:%LIB_SDK% prog.obj
Once you're comfortable that you understand this tutorial, have a look at the next one, which explains how to use make to save having to recompile source code that hasn't changed.
Home | About Me | Copyright © Neil Carter |
Last updated: 2016-03-02