How to Compile and Link with Visual C++

Huai-Ping Lee

November 30, 2007

Mysterious Linker Error

This problem happens to me so many times that I decided to write it down. How many times have you see the linker error "symbol already defined" or "unresolved symbol"? Unresolved symbols may be resolved by specifying appropriate library directories and library names in project Properties->Linker->General and Properties->Linker->Input. But sometimes after you resolved all the symbols, you get symbols that are already defined in libcmt.lib or msvcrt.lib or something like that. The linker will suggest you to turn on "Ignore All Default Libraries" option in project properties, but doing so will lead to more unresolved symbols. Sometimes "Ignore Specific Library" option can solve this problem (e.g., ignore libcmt.lib when something is already defined in it), but it does not always work. You need to get everything right.

MS Runtime Library

In project Properties->C/C++->Code Generation, there is a property called "Runtime Library." There are four options: Multi-threaded (/MT), Multi-threaded DLL (/MD), Multi-threaded Debug (/MTd), and Multi-threaded Debug DLL (/MDd). (We omit single-threaded and single-threaded debug because they are not allowed anymore since version 8.) The linker error originate from this: each option corresponds to a set of library files, and each set of library files contains all the symbols in C/C++ standard library. Therefore you have to avoid more than one of them appear in your project. It is not easy because each library you use are compiled and linked separately, and you may not remember what option you have used for each one.

So the solution is: check each library you used in the project. Make sure they are all compiled and linked with the same runtime library. Rebuild all of them with the same runtime library setting if necessary.

Case Study: Installing PETSc 2.3.3 with Visual C++ 8

This is the library that makes me want to write this web page. Due to the complexity of the makefile, I decided to follow the instruction in the official page. However, win32fe does not let you choose which runtime library to use. And If you want to optimize the code, you have to do it yourself. Look at the part of configuration parameter: --with-cc='win32fe cl --nodetect', note that we can add arguments to cl (Microsoft C++ Compiler) by adding -<arg>. For example, if we want to optimize speed, use
--with-cc='win32fe cl --nodetect -O2'
and for debug mode (no optimization), use
--with-cc='win32fe cl --nodetect -Od'
And in order to use C++ features, we can add
--with-cxx='win32fe cl --nodetect -Od' --with-clanguage=c++

And how about the runtime library? No matter what you add to the configuration parameter, it will automatically add -MT to it, overriding your setting. So the way to change it is to open the file $(PETSC_DIR)/bmake/petsconf, search for string "-MT" and replace it with the argument you want. Usually -MT and -MD are used with -O2 (release version), and -MTd/-MDd are used with -Od (debug version).

Another library to worry about is f2cblas and f2clapack that can be automatically downloaded and installed when configuring PETSc. But they also come with -MT option (and not optimized!) when installed. If you want to use another runtime library or perform code optimization for them, create a VC project for each of them, add all the .c files into corresponding VC project, and build them. Remember to add additional options
-DDOUBLE=double -DLONG=""
to C/C++->Command Line property. Otherwise the compiler will complain about DOUBLE and LONG that appear in the code.

Finally, you may run into a syntax error in $(PETSC_DIR)/bmake/$(PETSC_ARCH)/petscmachineinfo.h because of an additional newline. This file is generated right at the beginning of make all, so you have to move quickly! Open the file right after it is modified, fix the newline, and save it before it is used in compilation. And then wait for an hour with fingers crossed. (That's what I'm doing now.)


Back to Personal Page; Homepage