Friday, February 11, 2011

Windows XP both native and in VirtualBox

There are several good tutorials about similar topics, namely:
  1. How to migrate existing Windows installations to VirtualBox
  2. HOWTO: Windows XP in both VM and native
    but I couldn't find any that would describe what I was trying to achieve.

    What I had: Windows XP installed on a physical partition. What I wanted: Being able to run the installation both inside VirtualBox and also natively. I did not want to reinstall the WinXP installation nor did I want to have to fiddle with any Windows Genuine Disadvantage stuff. And I didn't want to break the native boot in the process. Also, as this was some über-corporate install I didn't want to have to ever use the WinXP install CD + its rescue console.

    Friday, August 20, 2010

    Using Glib::RefPtr with STL sorted containers

    It turns there's a bug in glibmm that prevents one from using Glib::RefPtr<T> with any of the STL sorted containers, e.g. std::map or std::set.

    The issue is a side effect of Glib::RefPtr<T>:
    • declaring operators == and !=
    • declaring operator bool()
    • not declaring operators <, <=, >, >=

    The operators == and != compare pointers for equality and work as expected. The operator bool() is defined to allow the following usage of a RefPtr:

    if (ref_ptr)
        puts("is non-null");
    else
        puts("is null");
    

    STL sorted containers need operator< on the type they contain. Assuming p1 and p2 are of type Glib::RefPtr<T>, the following compiles just fine:

    p1 < p2
    

    This in turn means that e.g. std::set<Glib::RefPtr<T> > my_map; compiles. Unfortunately, with current version of glibmm, this breaks badly at runtime.

    Why? As there's no custom operator<, the compiler interprets p1 < p2 like this:

    (bool)p1 < (bool)p2
    

    This is true iff p1 is NULL and p2 is non-NULL. The operators <=, >, >= also work on the results of operator bool(). So, depending on the pointers wrapped in p1 and p2, it's possible that the following would be true:

    p1 != p2 && !(p1 < p2) && !(p1 > p2)
    

    (this is true iff p1 and p2 wrap two different non-NULL pointers)

    There's a bug report for the issue.

    A workaround for the time being is to use a custom comparator like this:

    template<typename T>
    class RefPtrLess
    {
    public:
        bool operator() (const Glib::RefPtr<T> &a,
            const Glib::RefPtr<T> &b)
        {
            const T* const a_ptr = a.operator->();
            const T* const b_ptr = b.operator->();
    
            return a_ptr < b_ptr;
        }
    };
    
    typedef std::set<Glib::RefPtr<MyType>, RefPtrLess<MyType> > TMyTypeSet;
    

    Thursday, July 15, 2010

    Sending git patches from a different box

    Here's a solution to a problem that's been bothering me for a while: I wanted to create git patches from a box where there is no real MTA and so git send-email can't be used.

    One option is setting up real mail MTA or something simpler like msmtp or nullmailer. While this is the preferable, "true unix" way, I think plenty of ordinary linux users don't have this either.

    If, for whatever reason, this is not an option, but you have access to another box, where a MTA is set up correctly, you can do this:
    1. commit the change(s) into the git tree
    2. create the patch emails with: git format-patch --to to@addr ...
    3. transfer the produced patch email files to the box where you can send mails from
    4. send the email(s) with: /usr/sbin/sendmail -oi -t < mail-formatted.patch

    The first time I suggest you send the patch to yourself to verify it's all working as expected.

    This approach has a downside: You don't see the mails you sent in your MUA sent mail folder. Depending on your MUA, there are other ways of sending the mail. If you're using mutt, you might be in luck. But in general MUAs tend to mangle the patches. :-(

    Sunday, July 11, 2010

    Configuring linux kernel for use on ALIX 2 -- update

    Here is a short update on my older post on configuring linux kernel for use on ALIX2.

    The general points are still valid. The specific locations of the options might have changed. But to provide something more up to date, here is a working linux 2.6.34.1 configuration for ALIX 2.

    Use this only as a starting point to get a configuration that works well for you. There are plenty of options that are specific to my setup and you certainly want those changed. But you should be able to boot with this one.

    Linux kernel configuration -- using configuration from an older version

    As you probably know if you ever configured the linux kernel yourself (possibly by make menuconfig, or if you've been with linux long enough, by make config), the current kernel configuration that would be used for build is stored in the file .config.

    The options in the .config file depend on the kernel version the file was produced with. So, you can't directly use a config file from an older kernel with a newer one. But what you can do is use make oldconfig. This way, the config options that are still present in the current kernel keep their values and you are asked to configure only what options were added.

    To use this, just place the old .config file into the new kernel source tree and issue make oldconfig.

    Yeah, this post was inspired by the comment asking for newer ALIX 2 kernel config. A comment that I missed. Sorry. Mike. :-(

    Sunday, April 11, 2010

    Soft-float (FPU emulation) with DJGPP

    If you build a program using floating-point arithmetic with DJGPP and then try to run it on a box without a FPU (such as the 386, or 486SX), the program will die at the first attemt to use the floats.

    The solution for this is to tell DJGPP to use floating point emulation.

    While there is the -msoft-float GCC option, which seems to be recognized in the DJGPP port too, the option does not work under DJGPP.

    There is a DJGPP FAQ item about FPU emulation. It turns out the easiest way is to just add -lemu to linker options.

    Also, if you target the 386, add -march=i386 to compiler options. Otherwise the program might crash, as DJGPP can use an instruction that is not supported on the 386. (Not sure about 486. Is Pentium is the default target? Or the 486? Either way, it is good practice to specify -march as the lowest CPU the app needs to run on.)

    TurboVision with DJGPP and DOSEMU

    There's a nice port of the TUI library TurboVision to GCC. The port works on unix-like systems including linux, but it also still supports DOS (with DJGPP toolchain).

    Here's a guide on how to build the DOS version.

    First, grab the sources. I suggest you use the latest CVS version:
    cvs -d:pserver:anonymous@tvision.cvs.sourceforge.net:/cvsroot/tvision login
    (use empty password)
    cvs -z3 -d:pserver:anonymous@tvision.cvs.sourceforge.net:/cvsroot/tvision co -P tvision

    Then you need a DOS environment with DJGGP in it. DOSEMU + DJGPP worked ok for me (as detailed in my previous posts on the topic: 1 and 2).

    Have a look into doc/install/djgpp.txt. As the file explains, you will need some extra GNU tools installed inside your DJGPP directory. Here is the list of the files that worked for me at the time of this writing:
    • djdev203.zip - basic DJGPP runtime
    • bnu219b.zip - GNU Binutils
    • gcc442b.zip - gcc
    • gpp442b.zip - g++
    • mak3791b.zip - GNU Make
    • fil41b.zip - GNU fileutils
    • txt20b.zip - GNU textutils
    • shl2011b.zip - GNU sh-utils
    • perl588b.zip - Perl

    The TurboVision doc further mentions you will need GNU gettext. This is not a hard requirement -- you can build TurboVision without gettext support. If you do want to use gettext, be warned the procedure of installing GNU gettext is a bit complicated -- see the doc/install/djgpp.txt file and gnu/gtxt-010.40/djgpp/README inside the gettext archive (gtxt040b.zip).

    So now all you need to do is put a copy of the TurboVision sources in a place that can be reached from your DOS environment, change to that directory and fire up configure.bat. (If building without gettext, add the --no-intl option.)

    Unfortunately, you might just get this:
    C:\tvision>configure
    Configuring Turbo Vision v2.2.0 library
    
    Unknown OS, you must do things by yourself at conflib.pl line 903.
    Determining OS:
    

    The reason here is that the "uname" command (part of GNU sh-utils) prints out:

    c:\tvision>uname
    ??Unknow
    

    instead of what the TurboVision configure script expects ("MS-DOS").

    You either have to patch the configure script (hack the test if ($os=~/MS\-DOS/) to always pass, e.g. into if (1)) or change the uname command. (Quick and dirty hack to the uname command. Use the binary to overwrite the original djgpp\bin\uname.exe)

    Either way, now the configure script should pass:

    C:\tvision>configure --no-intl
    Configuring Turbo Vision v2.2.0 library
    
    Determining OS: DOS [djgpp]
    Looking for a working gcc: gcc OK
    C flags: -O2 -Wno-packed
    C++ flags: -O2 -Wno-packed
    Looking for the C++ compiler: gpp
    Checking Architecture: x86
    Looking for pointer size:  32 bits
    Looking for prefix: c:/djgpp
    Looking for GNU make: make
    Looking for GNU ar: ar
    Looking for install tool: install
    Looking for xgettext: no
    Checking DJGPP version: 2.0.3 OK
    Checking for international support: disabled by user request.
    Looking for allegro library: Bad command or filename - "allegro-config".
     no, disabling AlCon
    Checking endianess: little endian
    
    Generating Makefile
    Configuring makefiles: intl/dummy/Makefile 
    Configuring RHIDE: makes/rhide.env compat/rhide.env 
    Configuring RHIDE: examples/rhide.env 
    Generating configuration header: no changes
    Extracting from makes/librhtv.imk: processing
    Extracting from compat/compat.imk: processing
    Processing winnt/bccmake.in => winnt/Makefile
    Processing winnt/msvcmake.in => winnt/Makefile.nmk
    Makefiles for examples.
    Makefiles for translations.
    Processing intl/gnumake.in => intl/Makefile
    Processing redhat/librhtv.spec.in => redhat/librhtv-2.2.0.spec
    Processing qnxrtp/tvision.qpg.in => qnxrtp/tvision.qpg
    
    Succesful configuration!
    

    Then fire up make. With the default DOSEMU configuration you might end up with this error:
    cc1plus.exe: out of memory allocating 65536 bytes after a total of 6390696 bytes
    make.exe[1]: *** [../makes/obj/iffilelen.o] Error 1
    make.exe[1]: Leaving directory `c:/tvision/makes'
    make.exe: *** [static-lib] Error 2
    

    The solution is to increase the amount of DPMI memory in /etc/dosemu/dosemu.conf, e.g.: $_dpmi = (0x10000) instead of the default 0x5000.

    You can that use make examples to build some sample code. Start up e.g. examples\demo\demo.exe to see if the library compiled and works fine (works best with xdosemu, don't expect it to work in dumb mode :-)).

    To build your own programs with the TurboVision library, just add -IC:\tvision\include to compiler options and -Lc:\tvision\makes -lrhtv to linker options. (Substitute c:\tvision with your TurboVision sources path.)