Building a Simple Hello, World Application from the Command Line
Problem
You want to build a simple "Hello, World" program, such as that in Example 1-4.
Example 1-4. A simple "Hello, World" program
hello.cpp #include int main( ) { std::cout << "Hello, World! "; }
Solution
Follow these steps:
- Set any environment variables required by your toolset.
- Enter a command telling your compiler to compile and link your program.
Scripts for setting environment variables are listed in Table 1-5; these scripts are located in the same directory as your command-line tools (Table 1-3). If your toolset does not appear in Table 1-5, you can skip the first step. Otherwise, run the appropriate script from the command line, if you are using Windows, or source the script, if you are using Unix.
Toolset |
Script |
---|---|
Visual C++ |
vcvars32.bat |
Intel (Windows) |
iclvars.bat[2] |
Intel (Linux) |
iccvars.sh or iccvars.csh |
Metrowerks (Mac OS X) |
mwvars.sh or mwvars.csh[3] |
Metrowerks (Windows) |
cwenv.bat |
Comeau |
Same as the backend toolset |
[2] With earlier version of the Intel compiler, this script was named iccvars.bat.
[3] In versions of CodeWarrior prior to 10.0, there was a single csh script named mwvars.
Commands for compiling and linking hello.cpp are given in Table 1-6. To work properly, these commands require that your current directory is the directory containing hello.cpp and that the directory containing the command-line compiler appears in your PATH environment variable. If you ran a script in step 1, the latter condition will be satisfied automatically. It's also possible that when you installed your toolset, the setup utility added the directory containing the command-line tools to your PATH. Otherwise, you can either add the directory to your PATH, as shown in Table 1-7, or specify the full file pathname on the command line.
Toolset |
Command Line |
---|---|
GCC |
g++ -o hello hello.cpp |
Visual C++ |
cl -nologo -EHsc -GR -Zc:forScope -Zc:wchar_t -Fehello hello.cpp |
Intel (Windows) |
icl -nologo -EHsc -GR -Zc:forScope -Zc:wchar_t -Fehello hello.cpp |
Intel (Linux) |
icpc -o hello hello.cpp |
Metrowerks |
mwcc -wchar_t on -cwd include -o hello hello.cpp |
Comeau |
como -o hello hello.cpp |
Borland |
bcc32 -q -ehello hello.cpp |
Digital Mars |
dmc -Ae -Ar -I/stlport/stlport -o hello hello.cpp |
Shell |
Command line |
---|---|
bash, sh, ksh (Unix) |
export PATH=:$PATH |
csh, tsch (Unix) |
setenv PATH :$PATH |
cmd.exe (Windows) |
set PATH=;%PATH% |
For example, if you use Microsoft Visual Studio .NET 2003, and if it is installed in the standard location on the C drive, change to the directory containing hello.cpp and enter the commands shown below:
> "C:Program FilesMicrosoft Visual Studio .NET 2003Vc7in vcvars32.bat" Setting environment for using Microsoft Visual Studio .NET 2003 tools. (If you have another version of Visual Studio or Visual C++ installed and wish to use its tools from the command line, run vcvars32.bat for that version.) > cl -nologo -EHsc -GR -Zc:forScope -Zc:wchar_t -Fehello hello.cpp hello
You can now run your program:
> hello Hello, World!
Similarly, if you are using Intel 9.0 for Linux, and if it is installed in the standard location /opt/intel/cc/9.0, open a bash shell, change to the directory containing hello.cpp and enter the commands:
$ . /opt/intel/cc/9.0/bin/iccvars.sh $ icpc -o hello hello.cpp $ ./hello Hello, World!
Discussion
Environment variables are pairs of strings maintained by your system and accessible to running applications. Command-line tools frequently refer to environment variables to learn details about your system and to obtain configuration information that otherwise would have to be entered on the command line. The environment variable you will encounter most often is PATH, which stores a list of directories that are searched by the operating system when the name of an executable is entered on the command line using its simple name rather than its full pathname. On Windows, the directories in PATH are also searched when a dynamic library is loaded.
Command-line tools make use of environment variables on both Unix and Windows, but on Unix there is typically a dominant C++ compiler and the environment variables it requires are set by default to correct values. On Windows, however, there have traditionally been a number of competing C++ compilers; two different compilers will almost certainly have to look in different locations to find their standard headers and their compiled runtime support libraries, for example. It's, therefore, common for Windows toolsets to provide scripts that set a number of environment variables to record the locations of headers and libraries and other information.
One way to use such a script is to run it from the command line before invoking any of the command-line tools, as I demonstrated for Visual C++ and Intel 9.0 for Linux. It's also possible to make the environment variable settings permanent so that you don't have to run the script each time you start a command-line session; how this is done, depends on your operating system and on your shell. Changing your environment variables permanently is not always a good idea, however, since several toolsets may contain tools with the same name, causing the wrong tool to be invoked during the build process. For example, if you have multiple versions of Visual C++ installed, you must make sure to run the correct version of vcvars32.bat before using the command-line tools. As another example, the toolsets Visual C++ and Digital Mars both contain tools named link.exe and lib.exe.
Now let's look at the command lines in Table 1-7. Remember that you only need to be concerned with the row corresponding to your toolset. In general, the information passed to the compiler falls into four categories:
- The name(s) of the input files
- The name(s) of the output files
- The locations to search for files
- General configuration information
In Table 1-6, there is just a single input file, hello.cpp, and it is passed to the compiler simply by writing the name of the file on the command line. It doesn't matter where you place the name of the input file, as long as it doesn't appear in the middle of another command-line option. In Table 1-7, I placed hello.cpp at the very end of the command line.
There is also a single output file, hello.exe or hello, depending on the operating system. In this case, however, the way the file name is passed to the compiler depends on the toolset. Most toolsets use -o to specify an output executable, but Visual C++ and Intel for Windows use -Fe and Borland uses -e. Note that it's not necessary to specify the extension of an executable.
The only information in Table 1-7 that falls into the third category, locations to search for files, appears in the command line for Digital Mars. Since the STLPort library is not Digital Mars's built-in standard library, the compiler must be told, using the -I option, where to search for the STLPort headers. The STLPort headers are located in the /stlport/stlport subdirectory of the Digital Mars installation; I specified this directory in Table 1-7 using the notation /stlport/stlport. For more information on -I option, see Recipe 1.5.
Most of the command-line options in Table 1-7 fall into the fourth category: general configuration information. These options don't apply to any particular file; instead they enable or disable particular compiler features.
- The options -nologo (Visual C++ and Intel for Windows) and -q (Borland) tell the compiler not to print its name and version to the console. This makes the compiler's output easier to read.
- The options -EHsc (Visual C++ and Intel for Windows) and -Ae (Digital Mars) tell the compiler to enable C++ exception handling.
- The options -GR (Visual C++ and Intel for Windows) and -Ar (Digital Mars) tell the compiler to enable runtime type information (RTTI).
- The options -Zc:wchar_t (Visual C++ and Intel for Windows) and -wchar_t on (Metrowerks) tell the compiler to recognize wchar_t as a built-in type.
- The option -Zc:forScope (Visual C++ and Intel for Windows) tells the compiler to enforce modern for-scoping rules.
- The option -cwd include (Metrowerks) tells the compiler to begin searching for an included header in the directory of the source file that contains the include directive. This is the default behavior for all the toolsets but Metrowerks.
Next, let's consider a second solution to the original problem. Instead of compiling and linking with a single command, you can split the second step into two parts:
- Enter a command telling your compiler to compile your program to an object file without linking.
- Enter a command telling your linker to create an executable from the object file created in step 2a.
In this simple case, there's no reason to compile and link separately. Separate compilation and linking is frequently necessary, however, so it's important to know how to do it. For example, when creating a static library, you must compile without linking and then pass the resulting object files to the archiver.
The commands for compiling and linking in two steps are presented in Table 1-8 and Table 1-9. In several cases I've given an object file the extension o[bj] to indicate that a single command line is valid for Windows and Unix except for the extension of the object file.
Toolset |
Command line |
---|---|
GCC |
g++ -c -o hello.o hello.cpp |
Visual C++ |
cl -c -nologo -EHsc -GR -Zc:forScope -Zc:wchar_t -Fohello hello.cpp |
Intel (Windows) |
icl -c -nologo -EHsc -GR -Zc:forScope -Zc:wchar_t -Fohello hello.cpp |
Intel (Linux) |
icpc -c -o hello.o hello.cpp |
Metrowerks |
mwcc -c -wchar_t on -cwd include -o hello.o[bj]hello.cpp |
Comeau |
como -c -o hello.o[bj] hello.cpp |
Borland |
bcc32 -c -q -o hello.obj hello.cpp |
Digital Mars |
dmc -c -Ae -Ar -I/stlport/stlport -o hello.obj hello.cpp |
Toolset |
Command line |
---|---|
GCC |
g++ -o hello hello.o |
Visual C++ |
link -nologo -out:hello.exe hello.obj |
Intel (Windows) |
xilink -nologo -out:hello.exe hello.obj |
Intel (Linux) |
icpc -o hello hello.o |
Metrowerks |
mwld -o hello hello.o[bj] |
Comeau |
como no_prelink_verbose -o hello hello.o[bj] |
Borland |
bcc32 -q -ehello hello.cpp |
Digital Mars |
link -noi hello.obj, hello.exe,NUL,user32.lib kernel32.lib,, |
For example, to build the executable hello with the GCC toolset, change to the directory containing hello.cpp and enter the following commands:
$ g++ -c -o hello.o hello.cpp $ g++ -o hello hello.o
You can now run your program as follows:
$ ./hello Hello, World!
Table 1-9 is almost identical to Table 1-6. There are just two differences. First, the option -c is used to tell the compiler to compile without linking. Second, the output file is specified to be an object file hello.obj or hello.o rather than an executable. Most compilers use the option -o to specify the output file, but Visual C++ and Intel for Windows use the option -Fo. In addition, all the compilers except for Visual C++ and Intel for Windows require that the extension of the object file be specified.
By now, most of the command lines in Table 1-9 should be pretty easy to understand, so I'll just make two observations:
- The Digital Mars linker has an unusual command-line syntax, consisting of six comma-separated fields used for specifying different types of input files. For now you just need to know that the first field is for object files and the second is for the output file. The option -noi tells the linker to perform case-sensitive linking, which is necessary for C++ programs.
- The Borland linker, ilink32.exe, uses a syntax similar to that of Digital Mars. To simplify the command line, I've used the compiler, bcc32.exe, to perform the link step. Behind the scenes, bcc32.exe calls ilink32.exe.
See Also
Recipe 1.7 and Recipe 1.15