Posts Tagged ‘dev’

Difference between dup(0) and open(“/dev/fd/0″,…);

I believe APUE (2nd ed.; Sec. 3.16) is not correct.

APUE says fd = open("/dev/fd/0", mode); is equivalent to fd = dup (0);, and mode is completely ignored. It seems this is the case in Solaris, but wrong in Linux. (I don’t have access to other Unices at this moment.)

A test program:

01 #include <unistd.h>
02 #include <fcntl.h>
03
04 int main ()
05 {
06     close (0);
07     printf ("%dn", open ("a.txt", O_RDONLY)); // Should be 0
08     //int f2 = open ("/dev/fd/0", O_WRONLY);
09     int f2 = dup(0);
10     printf ("%dn", f2);
11     write (f2, "Hello worldn", 12);
12     return 0;
13 }

Let’s run the program with an empty a.txt. Certainly the write function in Line 11 is going to fail.

Now, let’s comment out Line 9 and uncomment line 8 and try it again.

First I ran it in Solaris, the write call still failed. The behavior is like what APUE tells us.

Try it again in Linux – It was successful!

It seems that in Linux, /dev/fd/0 is considered by open as nothing but a normal symlink to a.txt. So it returns a completely new descriptor instead of a duplicate of the old.

Let’s try it again with a shell script:

rm -f a.txt
touch a.txt
exec 0<a.txt
exec 3>/dev/fd/0
echo 'Hello world' >&3
cat a.txt

Run it in Linux (with DASH or BASH): Both outputed ‘Hello world’.

Run it in Solaris (with Bourne shell and BASH): Both failed, outputting nothing (Bourne shell) or failing with ‘Bad file number’ (BASH).

Conclusion:

(1) Solaris handles /dev/fd/.. specially, as APUE tells us;

(2) Linux simply consider /dev/fd/0 a symlink to the actual file.

(I’ll try later how Linux handles open("/dev/fd/0",mode) if the descriptor is an anonymous pipe or socket or something else that a normal symlink is unable to link to.

Kernels used in the above tests:

Linux: Linux desktop 2.6.28-gentoo #4 SMP Mon Jan 12 17:39:23 CST 2009 x86_64 Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz GenuineIntel GNU/Linux

Solaris: SunOS caesar 5.8 Generic_117350-51 sun4u sparc SUNW,Ultra-80 Solaris

Tags: , ,

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

Tags: ,

Determine the existence of a file in Makefile

Combine “wildcard” and “ifeq“. For example,

ifneq “$(wildcard Makefile.inc)” “”
include Makefile.inc
endif

GNU Make is powerful!

Tags: ,