Tuesday, June 10, 2008
Visual Studio tricks
Well, this is not really a trick but rather a trivial remark, but Visual Studio entertains some peculiar notion of "default libraries", which means, basically, that object file "knows" which basic system libraries like LIBCMT.LIB (basic C multithreaded library) or LIBCMTD.LIB (debugging version). That means that if you have certain 3-rd party or external libraries which you only have available to you in "non-debugging" version, and when try to link them with your project in "Debug" configuration, linker may want to include both LIBCMT.LIB and LIBCMTD.LIB, creating multiply-defined symbols and failing the build.
For some reason, problem (for me) only appears when I try to use STL library, which then causes diagnostics like this:
LIBCMTD.lib(dbgheap.obj) : error LNK2005: __heap_alloc already defined in LIBCMT.lib(malloc.obj) LIBCMTD.lib(dbgheap.obj) : error LNK2005: __recalloc already defined in LIBCMT.lib(recalloc.obj) LIBCMTD.lib(dbgheap.obj) : error LNK2005: __msize already defined in LIBCMT.lib(msize.obj) LIBCMTD.lib(malloc.obj) : error LNK2005: _V6_HeapAlloc already defined in LIBCMT.lib(malloc.obj) LIBCMTD.lib(dbghook.obj) : error LNK2005: __crt_debugger_hook already defined in LIBCMT.lib(dbghook.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: __get_sbh_threshold already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: __set_sbh_threshold already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: __set_amblksiz already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: __get_amblksiz already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: ___sbh_heap_init already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: ___sbh_find_block already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: ___sbh_free_block already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: ___sbh_alloc_block already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: ___sbh_alloc_new_region already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: ___sbh_alloc_new_group already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: ___sbh_resize_block already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: ___sbh_heapmin already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: ___sbh_heap_check already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(sbheap.obj) : error LNK2005: ___sbh_pHeaderDefer already defined in LIBCMT.lib(sbheap.obj) LIBCMTD.lib(isctype.obj) : error LNK2005: __isctype_l already defined in LIBCMT.lib(isctype.obj) LIBCMTD.lib(isctype.obj) : error LNK2005: __isctype already defined in LIBCMT.lib(isctype.obj)
The solution is to add option "/NODEFAULTLIB:LIBCMT" to the linker; this can (only) be done via manually editing linking options in project configuration:
Labels: visual studio, windows
Thursday, June 22, 2006
printf() and 64-bit integers
In the last post we talked about scanf(), so perhaps it would be proper now to discuss printf().
Good and reasonably brief manual page could be found here; then make sure to check Microsoft-specific formats here.
Some interesting features are there, e.g. you can use <'> format (single quote) to enable locale-specific number output (has no effect in C locale); you can also refer to specific argument by number, specify format width as a separate argument, and so on.
Let's consider one specific task to print some (large) 64-bit value. The basic problem is that you must know (1) what (integer) type to use to represent (at least) 64-bit integers, and (2) what printf() format does this type correspond to, if any.
On UNIX platforms long usually correspond to "machine word" (that is to say, has same size as pointer) so on 64-bit UNIX long is 64-bit and the following code:
printf ( "2^63 = %lu\n", 1L << 63 );
will print 2^63 = 9223372036854775808.
On 32-bit UNIX systems long is 32-bit but long long is 64-bit, and then the following code will work as expected:
printf ( "2^63 = %llu\n", (long long)1 << 63 )
(Gnu gcc understands 1LL, but I am not sure if other compilers do).
On Windows, however (with Microsoft compiler) approach is different and size of basic types does not change with CPU and so long is always 32-bit (same as int). Thus, in older Visual C++ systems you have to write:
printf ( "2^63 = %I64u\n", (__int64)1 << 63 );
... while in Visual .NET the above example with "long long" will work.
Labels: 64-bit, C, visual studio
Wednesday, May 10, 2006
Installing Python + ZSI on Windows
Now, who could ever think that in setting up my new laptop the most difficult thing would be to set up Python?
To be sure, Python is a very nice language, completely dynamic and OO, which allows you to implement a fast prototype for a complex object interaction. Then, you might want to re-implement in more "static" language like Java or just leave it Python if speed and reliability isn't among your first priorities.
However, another very nice feature of Python is a very well-done and well-supported Windows port, including a native Windows installer. There is a price to pay for this beauty: each Python release is implemented in specific Visual Studio C++/.NET version; e.g. all 2.4.* releases (latest stable release at this moment) are done in Visual Studio .NET 2003 (internal version = "7.1"); whereas 2.3.* releases are done in Visual C++ 6.0 (internal version = "6.0"). That said, the latest suite from Microsoft (right now) is Visual Studio .NET 2005 (internal version = "8.0"), and this is exactly what I have (by default) installed on my new laptop.
Praises to Python Windows port above notwithstanding, file msvccompiler.py, part of standard Python distribution, does not do the best possible job at detecting user's Visual Studio environment. It has not occurred to the author that the latest version it knows about (7.1) will sooner or later be superseded with a newer one; as as result, on my laptop an attempt to install any Python extension that contains C code fails with dubious message "The .NET Framework SDK needs to be installed before building extensions for Python"; message sure to puzzle someone who knows damn well .NET SDK is installed on his machine...
As a final remark, I must say that I am using Python for (effectively) RPC calls via TCP/IP using SOAP and Python extension called ZSI (along with mod-python on the server). I was using version 1.7 of ZSI, which only worked for me after applying simple patch to the client code.
Anyway, let me without further adieu present my sequence of actions:- Installed binary distribution of Python for Windows; latest stable release 2.4.3;
- Downloaded and installed latest ZSI build 2.0rc2 (no C code so installed flawlessly); I noticed that client code has changed dramatically since 1.7 so that my patch may be no longer required;
- Run test script. It appears to fail because the API (specifically function ZSI.client.Binding) changed in an incompatible way. What's more, there is no API to tell me version number, so there is no simple way to write client code compatible with both 1.7 and post-1.7 ZSI API. After a while, I solve this problem by parsing function documentation string Binding.__init__.__doc__;
- Run test script. It fails complaining that it cannot load "xml.dom.ext.reader";
- This is actually very peculiar, since Python is of course well-equipped with XML DOM parsers; but yes, I vaguely remember that indeed for some mysterious reasons ZSI depends on an external expat-based XML parser;
- OK, I go ahead and download the latest source release of PyXML (I mistakenly think binaries are not available for Python 2.4 since this version of PyXML is rather old, but in fact they are);
- Build fails with message "The .NET Framework SDK needs to be installed before building extensions for Python" (see above);
- I try to modify file msvccompiler.py to convince it to use my installed version of Visual Studio. After a while, it does work and installation of PyXML succeeds;
- Test script now crashes Python executable. This is perhaps related to incompatibilities of two dynamic runtimes that Python itself (7.1) and PyXML are trying to load;
- I download source distribution of Python (2.4) and try to compile it from source using Visual Studio 2005. It builds simple python.exe and it crashes on startup, invoking debugger and stalling build;
- I remove all previous installations of Python and install older Python version 2.3 from the scratch (binaries) along with Visual C++ 6.0 environment;
- Following the steps described above, both ZSI (2.0-rc2) and PyXML now install successfully;
- Test script fails somewhere in ZSI client code. An attempt to debug it reveals that function Binding::RPC is called from _Caller with (default) argument replytype=None, which then fails in parsing. An attempt to fix this (TC.Any()) improves the result a little bit, but not all that much. It appears that ZSI changed XML marshalling logic and thus I cannot have post-1.7 client and 1.7 server;
- I try to install older version of ZSI (1.7 + my patch) above the previously installed (Python extension installation mechanism does not give me any simple way to uninstall); this results in empty SOAP message being passed to the server;
- Desperate, I simply erase the sub-directory d:\Python23\Lib\site-packages\ZSI and reinstall ZSI 1.7;
- Run the test script; finally it works.
Labels: python, SOAP, visual studio, windows