cross distcc

It is possible to distribute compilations to machines with different architectures.

Here is an example, to allow distributing tasks from a 64-bit system (x86_64) to 32-bit systems (i686):

First of all, both the client and servers should have distcc installed, of course. Then run the distcc daemon at the servers. Be careful so that they are not refusing connections from the client.

The distcc servers should also have the corresponding cross toolchains installed.
In Gentoo, this is simple. Emerge crossdev and run crossdev --target x86_64-pc-linux-gnu. (Experience tells us it is better to stip -march=... from CFLAGS when building the cross toolchain, otherwise we may (or may not) encounter strange errors, though some options like -march=nocona are valid on both i686 and x86_64. The reason is beyond me...)

Then commands x86_64-pc-linux-gnu-{gcc,g++} should be available.

Most source packages are created with autotools, so they honor the environment variables CC and CXX. At the client end, export CC='distcc x86_64-pc-linux-gnu-gcc' and CXX='distcc x86_64-pc-linux-gnu-g++' before compiling.

It is important to use the full compiler name including the host architecutre (x86_64-pc-linux-gnu in this example). Otherwise the distcc servers call the native compilers, resulting in incompatible object files.

Alternatively you may want to use the “transparent” method of calling distcc: PATH="/usr/lib/distcc/bin:$PATH" make. This does not work automatically. Instead, it is necessary to use a wrapper script to make sure the architecture is explicitly specified:
# cd /usr/lib/distcc/bin
# rm cc c++ gcc g++
# echo '#!/bin/bash' > distcc-wrapper
# echo 'exec /usr/lib/distcc/bin/x86_64-pc-linux-gnu-g${0:$[-2]} "$@"' >> distcc-wrapper
# chmod +x distcc-wrapper
# ln -s distcc-wrapper cc
# ln -s distcc-wrapper c++
# ln -s distcc-wrapper gcc
# ln -s distcc-wrapper g++

Reference
[1] DistCC Cross-compiling Guide - Gentoo Documentation

How BASH Changes Terminal Window Title

In many distributions bash automatically changes the terminal title. I thought it was hardcoded in bash, but it turns out to be not. It is usually implemented with PROMPT_COMMAND.

Environment variable $PROMPT_COMMAND defines the command to be automatically executed before displaying the primary prompt (i.e. $PS1). It is set by a script that is sourced by interative instances of bash. In Gentoo it is in /etc/bash/bashrc:
case ${TERM} in
    xterm*|rxvt*|Eterm|aterm|kterm|gnome*|interix)
        PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*}:${PWD/$HOME/~}\007"'
        ;;
    screen)
        PROMPT_COMMAND='echo -ne "\033_${USER}@${HOSTNAME%%.*}:${PWD/$HOME/~}\033\\"'
        ;;
esac

In fact, the first version above also works with newer versions of screen.

MATLAB matrices are in column-major storage

Authors of each and every high-level programming language claim you only have to care the semantics of its statements without worrying about its internal implementation. Unfortunately, this can hardly be true.

Today I was working on some MATLAB codes. One of them scales each row of a sparse matrix to make its 1-norm equal to 1. The matrix I worked on was 20000×20000, with 153306 nonzero entries.

This is the first version:
for k = 1:N
 s = sum(P(k,:));
 if s ~= 0
  P(k,:) = P(k,:)/s;
 end
end
This did not stop in 20 seconds, until I pressed Control-C.

This is the second version:
P = P';
for k = 1:N
 s = sum(P(:,k));
 if s ~= 0
  P(:,k) = P(:,k)/s;
 end
end
P = P';
This finished within one second.

[All entries of matrix P are known to be positive, so I simply use sum to get the 1-norm of a row/column.]

The reason is simple. MATLAB internally stores sparse matrices in compressed column format[1]. Therefore, it is many times more expensive to extract or insert a row than column.

ps. For dense matrices, MATLAB also uses column-major formats, following the FORTRAN convention, though MATLAB is itself written in C (and the GUI in Java) [1].

References

[1] J. Gilbert, C. Moler and R. Schreiber. Sparse matrices in MATLAB: Design and implementation. SIAM Journal on Matrix Analysis, 1992.

GCC #pragma pack bug

#pragma pack is accepted by many C/C++ compilers as the de facto standard grammar to handle alignment of variables.

However there is an old bug in GCC, reported many times, the first of which was in 2002, still not fixed now.
#include <cstdio>
using namespace std;

#pragma pack(1)
template <typename T>
struct A {
    char a;
    int b;
};
A<int> x;
#pragma pack(2)
A<char> y;
#pragma pack(4)
A<short> z;

int main()
{
    printf ("%d %d %d\n", sizeof x,sizeof y,sizeof z);
    return 0;
}

This gives 5 6 8 instead of 5 5 5 as we may expect. (VC++ and ICC both give the more reasonable 5 5 5.)

This example is not very bad. Even worse is, that this bug can damage programs that use STL. Here is an example:

a.cpp:
#include <cstdio>
#include <map>
using namespace std;

#pragma pack(1)
void foo (const map<short,const char*> &x)
{
    for (map<short,const char*>::const_iterator it=x.begin();
            it!=x.end(); ++it)
        printf ("%d %s\n", it->first, it->second);
}

b.cpp:
#include <map>
using namespace std;

void foo (const map<short,const char *> &);

int main()
{
    map<short, const char *> x;
    x[0] = "Hello";
    x[1] = "World";
    foo (x);
}

Compile a.cpp and b.cpp separately and link them together. This program segfaults if compiled with GCC, but works well with ICC or VC++.

In conclusion, for better portability and/or reliability, never use #pragma pack unless absolutely necessary. If really unavoidable, always push and pop immediately before and after the structure definition. (If the program is intended to be compiled by GCC/ICC only, it is better to use the more reliable GCC-specific __attribute__((__packed__)).)

PS. It seems Sun CC (shipped with Solaris) also has this bug. It fails for the first example here, but for the second it works well. I don't know how manages to align pair<short,const char *> correctly...

su without password

Google returns a lot of meaningful results for “sudo without password” and “ssh without password.” I don’t know why googling “su without password” gives no useful info.

To allow a user to become root with su without entering the password, edit /etc/pam.d/su.

For example, in Gentoo (should be the same or similar in other distros) uncommenting the following line allows users in group wheel to su without password:
auth sufficient pam_wheel.so use_uid trust

Send Ctrl-A to sessions in SCREEN

C-A servers as the command hotkey in SCREEN. To send Ctrl-A to the session in SCREEN, simply use C-A a.

Example: the shell in SCREEN calls ssh, and SCREEN is again used in the remote machine. To detach the session in the remote SCREEN, press C-A a d.

BASH’s ‘read’ built-in supports '\0' as delimiter

I thought it was impossible to use '\0' as a delimiter in bash, but noticed yesterday that Gentoo’s ebuild.sh had pipelines like this:
find ..... -print0 |
while read -r -d $'\0' x; do
# Do something with file $x
done

This makes it possible to handle any strange filenames correctly, even if the filename contains newline ('\n') or carriage return ('\r') characters. (Some other commands, including sort and xargs, have options to make null character the delimiter based on the same reason.)

Because BASH internally uses C-style strings, in which '\0' is the terminator, read -d $'\0' is essentially equivalent to read -d ''. This is why I believed read did not accept null-delimited strings. However, it turns out that BASH actually handles this correctly.

I checked BASH’s souce code and found the delimiter was simply determined by delim = *list_optarg; (bash-3.2/builtins/read.def, line 296) where list_optarg points to the argument following -d. Therefore, it makes no difference to the value of delim whether $'\0' or '' is used.