Win7 KVM VGA Passthrough (gtx 750)

I have a Win7 qemu VM passed a gtx 750 and a keyboard+mouse, and the following is a rough guide, inspired from other similar guides which didn’t quite work for me or weren’t informative enough.


I’m running 64bit Debian Jessie with Qemu/kvm from stock apt. I’m not using libvirt for, as the older version in Debian’s apt does not support -cpu kvm=off among other things. This is a file server/VM host that I choose to use headless, and now it also functions as a very capable gaming rig thanks to virtualization.

root@machina:~# qemu-system-x86_64 -version
QEMU emulator version 2.1.2 (Debian 1:2.1+dfsg-12), Copyright (c) 2003-2008 Fabrice Bellard

Hardware (bought from Fry’s in Sunnyvale, CA):

The most important part of that CPU is that it supports vt-d which is used for hardware pass through to VMs. It’s also damn fast which helps for gaming performance.

I chose that Gigabyte brand of board as ones related to it have been reported working. I have since added the working setup here to that doc.

Also, I’m using nvidia driver version 335.23 (the oldest that supports this card) as apparently that is the last to require -cpu kvm=off. I have not tried newer drivers as this one works very well, and if it ain’t broke slow don’t fix it.

I’m using win7 as the tablet-UI in later Windows releases suck ass and I had an iso lying around already.

Step 1: Get a supported kernel and tweak grub boot options

Step 1.1:

Because I am using intel integrated graphics, I’m using 3.18.0 with the i915 patches (google). I should be using a newer kernel instead as this one is hella old, but it works and this box isn’t internet facing. I recommend compiling the kernel on an SSD.

I should include a guide for this later for those who aren’t used to compiling kernels.

Step 1.2:

Set the following in /etc/default/grub. Enable i915 patch and intel_iommu.

GRUB_CMDLINE_LINUX="intel_iommu=on i915.enable_hd_vgaarb=1"

Run these:

sudo update-grub

Step 2: Device finding

Make sure your iommu groups are correct.

These are the devices I’m passing. Note the preceding numbers and the vendor:device id pairs:

joe@machina:~$ lspci -vnn | grep -i nvidia
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GM107 [GeForce GTX 750] [10de:1381] (rev a2) (prog-if 00 [VGA controller])
01:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:0fbc] (rev a1)

Also my separate keyboard/mouse. (A usb apple keyboard from ~2001 + a cheap usb mouse + cheap usb sound card + wired xbox 360 controller)

joe@machina:~$ lsusb 
Bus 003 Device 009: ID 093a:2510 Pixart Imaging, Inc. Optical Mouse
Bus 003 Device 006: ID 05ac:0204 Apple, Inc. 
Bus 003 Device 011: ID 0d8c:000c C-Media Electronics, Inc. Audio Adapter
Bus 003 Device 010: ID 045e:028e Microsoft Corp. Xbox360 Controller

Step 3: Networking

Configure qemu networking. I have my eth0 bridged to br0 (that is a separate article), and the following conf needs to exist to pass br0 to the VM. I am using qemu’s bridge helper rather than creating the tap devices manually. br0 corresponds to the bridge name in both snippets below.

qemu bridge helper (this file won’t exist by default):
root@machina:~# cat /etc/qemu/bridge.conf 
allow br0
network bridging conf

There are lots of ways of doing this, but this is mine. If you choose to go this route, install bridge-utils with apt.

root@machina:~# cat /etc/network/interfaces
auto lo
iface lo inet loopback

iface eth0 inet manual
auto br0
iface br0 inet dhcp
bridge_ports eth0

Step 4: VM Start Script

Script I run. Interesting parts that will change for your setup are in bold.

vfiobind() {
        vendor=$(cat /sys/bus/pci/devices/$dev/vendor)
        device=$(cat /sys/bus/pci/devices/$dev/device)
        if [ -e /sys/bus/pci/devices/$dev/driver ]; then
                echo $dev > /sys/bus/pci/devices/$dev/driver/unbind
        echo $vendor $device > /sys/bus/pci/drivers/vfio-pci/new_id


modprobe vfio-pci

for line in 0000:01:00.0 0000:01:00.1; do
vfiobind $line

sudo qemu-system-x86_64 -enable-kvm -M q35 -m 4096 -cpu host,kvm=off \
-smp 4,sockets=1,cores=4,threads=1 \
-bios /usr/share/seabios/bios.bin  -vga none \
-device ioh3420,bus=pcie.0,addr=1c.0,multifunction=on,port=1,chassis=1,id=root.1 \
-device vfio-pci,host=01:00.0,bus=root.1,addr=00.0,multifunction=on,x-vga=on \
-device vfio-pci,host=01:00.1,bus=root.1,addr=00.1 \
-drive file=/dev/vg-ssd/vm-win7,id=disk,format=raw,if=virtio \
-drive file=/dev/vg-ssd/vm-win7-slice2,format=raw,if=virtio \
-usb -usbdevice host:093a:2510 -usbdevice host:05ac:0204 \
-usb -usbdevice host:045e:028e \
-usb -usbdevice host:0d8c:000c \
-boot menu=on \
-netdev tap,helper=/usr/lib/qemu/qemu-bridge-helper,id=hn0 -device virtio-net-pci,netdev=hn0,id=nic1 \
-vnc :2


  • It is highly irresponsible of me to run this as root, but it’s easy. If the guest manages privilege escalation due to a bug in kvm/qemu (like the floppy driver one months back), your box might get rooted and/or fucked. Keep your qemu packages updated! It might help that I’m using Debian stable rather than arch, as qemu might only be updated for security patches rather than new features which could break this.
  • Without -vnc :2, this command requires a working GUI with SDL to run which sucks as I run this in screen from ssh. I also like being able to connect via VNC. This is not at all a boot menu or a gui interface to the VM, but rather a qemu debug command prompt. I recommend restricting access to this (port 5902) using iptables.
  • kvm=off stops qemu from advertising the fact that it is running KVM to the guest. This is needed for newer nvidia drivers as nvidia refuses to work if it thinks its a VM
  • -cpu host exposes all of the host CPUs to the VM nearly verbatim. From what I’ve read, this is the best option for performance.
  • I’m giving it 4GB of ram (I have 16GB on the host) which is apparently plenty.
  • The path to the seabios binary changes slightly per debian qemu release (dpkg -L seabios | grep bios.bin)
  • I store my VM as LVM LVs/slices on an SSD. I hear that passing raw block devices (eg /dev/sd$X) to VMs doesn’t fare well, and I like being able to carve up the SSDs into other block devices for other VMs/etc. There’s also a possibility that using an LVM LV slightly avoids filesystem overhead you’d get if you were using a sparse file on ext4/etc.
  • -boot menu=on probably does not need to be there but I like the verbosity it gives during the boot process
  • That vfio bind function has been copy/pasted around various other articles.
  • The modprobe stanza might not be needed.

During my install, I used the following. After I installed all of the virtio drivers, I stopped using the realtek nic and ide disks:

sudo qemu-system-x86_64 -enable-kvm -M q35 -m 4096 -cpu host,kvm=off \
-smp 4,sockets=1,cores=4,threads=1 \
-bios /usr/share/seabios/bios.bin  -vga none \
-device ioh3420,bus=pcie.0,addr=1c.0,multifunction=on,port=1,chassis=1,id=root.1 \
-device vfio-pci,host=01:00.0,bus=root.1,addr=00.0,multifunction=on,x-vga=on \
-device vfio-pci,host=01:00.1,bus=root.1,addr=00.1 \
-drive file=/dev/vg-ssd/vm-win7,id=disk,format=raw -device ide-hd,bus=ide.0,drive=disk \
-drive file=/dev/vg-ssd/vm-win7-slice2,id=disk2,format=raw -device ide-hd,bus=ide.1,drive=disk2 \
-usb -usbdevice host:093a:2510 -usbdevice host:05ac:0204 \
-boot menu=on \
-netdev tap,helper=/usr/lib/qemu/qemu-bridge-helper,id=hn0 -device rtl8139,netdev=hn0,id=nic1 \
-drive file=/srv/ssd/misc/vm/win7.iso,id=isocd -device ide-cd,bus=ide.1,drive=isocd

Appendix 1: screenshots!

  • My mac mini connected as a steam in-house streaming client to the win7 VM: link
  • Windows experience index: link
  • Speccy/device manager (seeing a geforce card listed with the VirtIO drivers is mad trippy: link
  • VirtIO drivers make the network cards think they’re 10gig: link
  • htop on host showing the qemu procs: link

Appendix 2: links

There are some very good docs on this subject, and the steps I am using here is shamelessy ripped from them, albeit tweaked a little. Highlights/credits:

  • Alex’s Wiki which should be treated as source of truth for the subject:
  • Google spreadsheet containing list of supported/unsupported hardware: link
  • Forum thread with useful info: link

Moving from Android to iPhone/iOS

My last iPhone was in 2009, and I switched after around a year when I got sick of AT@T, which used to be the sole carrier for iPhones. Since then I used and loved the Motorola Droid and its Motorola successors. Yesterday, I took the plunge and got an iPhone 5S. Despite the iPhone 6 coming out next month, the feeling of nostalgia was too overbearing to make me want to wait.

Being a long term Linux on the desktop user, I jumped on the apple band wagon for computers around a year ago. Switched my primary desktop from Debian Unstable/sid on home-built hardware to a Mac Mini running OS  X. Later on, bought a macbook air. My day job provides me with a macbook pro and a RHEL desktop, which I choose to use headless via ssh/mosh. I’ve taken to the “Linux/BSD on servers and OS X on desktops” paradigm.

I don’t have any major complaints with OS X, mainly because most of the open source apps I used on Linux work just as well (Firefox, Thunderbird, Filezilla, Chrome, others) and my favorite CLI apps either come bundled (vim, screen, bash, ssh) or are easily installable with brew or compilable from source. You get the ability to use the best of open source, as well as apps which don’t run on Linux such as MS Office and the Adobe suite, without the headache of tweaking Wine. Setting up netatalk/AFP is also nicer and more integrated than using plain NFS to share files from my Debian NAS.

However, there are several complaints and gripes I have about iOS, and I felt like making a blog post to list them:

Things I don’t like about iOS:

– Can’t play OGG/FLAC. My music collection is a hodgepodge of mp3/wma/flac/m4a/ogg/flac, all of which Nightingale (and Rhythmbox) play without issue. That Python script I wrote to convert a ton of music files to low quality MP3 may finally come in handy.

– Can’t save non-picture files to the device, such as PDFs or tarballs or anything else you may want to occasionally save.

– Can’t browse filesystem. No external storage like an SD card or similar.

– No SwiftKey alternative. I hear that a SwiftKey iOS port is in development, and I’m looking forward to it.

– No app privilege limitation or ability to see what functionality of your phone is given to apps. I don’t particularly care that much though.

– Can’t transfer files/pictures via Bluetooth. I had gotten accustomed to taking a picture and using the bluetooth file transfer app in OS X to get them off my phone. Emailing pictures I take to myself is a bit of an inconvenience.

– Airdrop can’t copy files between OS X and iPhones. I had guessed there would be some form of nice integration between the two platforms, aside from iTunes. Luckily FaceTime is immune to this limitation.

– No 4chan browser apps in appstore. Mimi for android is fantastic but apparently apple kicked off all equivalent apps years ago. It’s a little tempting to make a 4chan browser in Swift and see my luck for getting it added.

– I don’t think you can install arbitrary apps in same way you can on android by copying over a .APK package and accepting the security warnings.

– No floating chat heads in Facebook Messenger. I assume this is due to less functionality being given to apps.

– NSA is probably watching everything I do, but this con likely applies to Android devices as well.

The pros:

– Finger print unlock. I didn’t know it came with this so it was a bit of a pleasant surprise when the setup wizard prompted for my thumb print. Makes waking it from sleep and authorizing purchases very convenient.

– Higher quality apps. The apps that have their Android equivalents are more polished. I attribute this more to app devs feeling that there may be more iPhone users than android users, or that they’re just more likely to pay for apps. Examples: Uber, Yelp, Facebook, Wayze, Kindle, others.

– The device (iPhone 5S) itself is beautifully made. Metal case + glass screen. The two android models I’ve had were just plastic, and I feel that’s how most of them are. This is also a con as it’s more likely to crack and break whereas I put my droids through hell without their screens getting cracked.

– Lightning connector is better than micro USB. Akin to the new power connectors for macbooks, it doesn’t have a “right side up” way of connecting.

– Camera/photo app offers cropping and adding filters to pictures. I imagine that newer android versions have this built in but I haven’t looked.

– FaceTime is awesome.

– GoogleHangout app provides good enough access and integration to gchat, and the ability to add google accounts to the phone’s internal account system provides easy access to my google contacts.


The restrictions and missing features are likely all “by design.” It’d really suck if Apple applied this approach to the same extent to OS X.

I’m likely going to use the iPhone 5S for a year or so and then go back to an android device made by Motorola.

Deleting SVN Revisions

Say you have a large SVN repo with 617 commits. You want to physically delete the last 6 so you’re back to r611. You do not want the data contained in these revisions to exist so svn revert is not appropriate.

The most elegant way of killing off r612-r617 is to make a SVN dump up until revision r611 and then restore from it.

Dump the server-side SVN folder and then move it aside:

svnadmin dump myrepo/ -r r1:r611 > myrepo.dump
mv myrepo myrepo.old

Recreate a fresh repo and import the dump
svnadmin create myrepo
svnadmin load myrepo < myrepo.dump

You’re done.

desktop notifications for irssi nick highlights

I am a long term user of screen+irssi, a quite common way of using IRC for unix-inclined people neckbeards. One problem with this approach is that you will not be notified of events such as nick highlighting and PMs outside of your terminal window.

A quick hack is to use the fnotify irssi script to write highlights to a text file, and then a quick shell one liner to continually read events (lines) from this file and alert you via the gui. This post assumes basic knowledge of irssi, which I’m not going to cover here.

Install fnotify:

wget -P ~/.irssi/

Run it inside irssi:
/run fnotify
[00:16] ~~~Irssi: Loaded script fnotify

Run this on your desktop and let it run indefinitely, and you’ll enjoy being notified of important events instead of finding them after the fact:

tail -n0 -f .irssi/fnotify | xargs -I{} xmessage "{}"

Protip: the xmessage command is a really ugly X11 built-in command and is primarily suited to minimal window managers such as fluxbox. Its notification popups will look quite out of place in a full blown desktop such as Gnome or KDE; using a different command such as notify-send or similar may be more appropriate.

Realtime stats of dd

There are at least two ways of getting the progress of the dd command. One is sending the dd command the -USR1 kill signal, which will cause it to print out its current progress to stderr:

kill -USR1 `pidof dd`

The other way is to examine the fdinfo file (either 0 or 1) for the dd process under /proc to see how much data has currently been copied. This is more efficient and way faster than sending dd a signal as it’s pulling directly from /proc and instead of waiting for dd to catch the signal.

root@debian:~# printf '%0.3fGB\n' $(bc -l <<< "$(awk '{if ($1 ~ "pos") print $2}' /proc/`pidof dd`/fdinfo/0) / 1073741824") 15.310GB root@debian:~#

Run it in a loop for stats every few seconds:

while :; do clear; printf '%0.3fGB\n' $(bc -l <<< "$(awk '{if ($1 ~ "pos") print $2}' /proc/`pidof dd`/fdinfo/0) / 1073741824"); sleep 2; done

Drastically increase mkfs.ext4 speed

Every now and then, you might want to create an ext4 filesystem on a block device spanning several terabytes, and this is almost always a really long process, taking up to several hours or even days.

There is a little known trick that can significantly reduce the amount of time needed to create ext4 filesystems:

mkfs.ext4 -E lazy_itable_init=1

The lazy_itable_init flag is default on newer versions of e2fsprogs, and the above snippet works on systems as old as Centos5.

su+screen: “Cannot open your terminal ‘/dev/pts/0′ – please check.”

Quick tip this time.

Often enough, one is logged in as root and decides to su – to an underprivileged user. Due to the tty for the root shell being owned by the user root, the su’d environment is unable to run screen:

root@whitegirl:~# su - joe
joe@whitegirl:~$ screen
Cannot open your terminal '/dev/pts/0' - please check.

This is resolved by setting the owner of the terminal device to the target user before running su, so the user then has write privileges on the pseudo teletype device:

root@whitegirl:~# chown joe `tty`
root@whitegirl:~# su - joe
joe@whitegirl:~$ screen

And then revert it when done

[screen is terminating]
joe@whitegirl:~$ logout
root@whitegirl:~# chown root `tty`

Diskless Debian Linux booting via dhcp/pxe/nfs/tftp/aufs

Want to boot a (possibly minimal) installation of Debian off the network using a read-only NFS share as the root filesystem, such that each netbooted machine has / mounted read-only over NFS and all writes are done to memory? Read on!

This assumes you are using a Linux computer as your router, which will be running Debian and hosting the local version of Debian we will be serving to clients which are PXE booting. This could be seen as a second part of my tutorial on making a Debian box a router , as it assumes your local network is still and the dhcp/nfs/tftp server’s IP is

First off, we’ll need deboostrap, nfs, tftpd, and syslinux. Install them:

apt-get install tftp-hpa nfs-kernel-server debootstrap syslinux

We will store our initrd and boot loader under /srv/tftp and our NFS root filesystem under /srv/nfsroot

mkdir -p /srv/tftp /srv/nfsroot

Our nfsroot needs to be mountable via NFS. Export it read-only to our local network by putting the following in /etc/exports


We will be booting to a custom Debian install. Install it in /srv/nfsroot using Debootstrap:

debootstrap stable /srv/nfsroot

Now we need to install some packages in the NFS installation of Debian:

chroot /srv/nfsroot apt-get update
chroot /srv/nfsroot apt-get install initramfs-tools linux-image-2.6.32-5-amd64

Configure its initramfs to generate NFS-booting initrd’s

sed 's/BOOT=local/BOOT=nfs/' -i /srv/nfsroot/etc/initramfs-tools/initramfs.conf

We’ll need the aufs module

echo aufs >> /srv/nfsroot/etc/initramfs-tools/modules

Create the file /srv/nfsroot/etc/initramfs-tools/scripts/init-bottom/aufs give it executable permissions and fill it with the following

modprobe aufs
mkdir /ro /rw /aufs
mount -t tmpfs tmpfs /rw -o noatime,mode=0755
mount --move $rootmnt /ro
mount -t aufs aufs /aufs -o noatime,dirs=/rw:/ro=ro
mkdir -p /aufs/rw /aufs/ro
mount --move /ro /aufs/ro
mount --move /rw /aufs/rw
mount --move /aufs /root
exit 0

Generate initrd

update-initramfs -k

Copy generated initrd, kernel image, and pxe bootloader to tftp root and create folder for pxe config

cp /srv/nfsroot/boot/initrd.img-2.6.32-5-amd64 /srv/tftp/
cp /srv/nfsroot/boot/vmlinuz-2.6.32-5-amd64 /srv/tftp/
cp /usr/lib/syslinux/pxelinux.0 /srv/tftp
mkdir /srv/tftp/pxelinux.cfg

Configure boot loader. Put the following into /srv/tftp/pxelinux.cfg/default

default Debian
prompt 1
timeout 10
label Debian
kernel vmlinuz-2.6.32-5-amd64
append ro initrd=initrd.img-2.6.32-5-amd64 root=/dev/nfs ip=dhcp nfsroot=

Configure tftp’s /etc/default/tftpd-hpa


Add these lines to your dhcp config file /etc/dhcp/dhcpd.conf

allow bootp;
allow booting;

Restart some services:

/etc/init.d/isc-dhcp-server restart
/etc/init.d/tftpd-hpa restart
exportfs -ra

At this point, configuration is done and you should be good to go. You might want to reset the root password on the nfs debian install:

chroot /srv/nfsroot passwd root


Linux as a router with iptables, bind9, and dhcpd

There are some benefits to using a Linux box as a router. You get full access to the power of iptables, can host stuff directly on the box itself rather than having forwarding ports to other machines on your network, can torrent with way more peers as the box will support more connections than a usual home router, use the router itself as a fileserver/seedbox, etc.

The network setup this entails is as follows: [Modem] – [Linux box/router] – [switch] – [other machines on your network]

For the box itself you will need two network interfaces, one for your modem and one for your switch. Throughout this tutorial, we will be referring to the one connected to your modem as eth0 and the one connected to your switch as eth1.

Additionally, the network range I will be using for your local network will be

This tutorial is intended for Debian/Ubuntu but porting it to CentOS is trivial.

Step 0 – Configure network interfaces

Debian uses /etc/network/interfaces for assigning IP addresses and so on to its network interfaces. You can use the following and tweak it to your needs.

# Loopback interface. Omitting this will cause weird problems
auto lo
iface lo inet loopback

# The interface connected to the modem. This implies you do not
# have a static IP address from your ISP. If you do, you can
# use the same notation eth1 uses below, with the addition of a 
# gateway clause
auto eth0
iface eth0 inet dhcp

# Interface bound to local network. 
auto eth1
iface eth1 inet static

Step 1 – Install packages

We will need dhcpd to provide DHCP to our local network and bind9 to provide DNS lookups

apt-get install isc-dhcp-server bind9

Step 2 – Configure dhcpd

As mentioned earlier, we’ll be using as our IP range. Additionally, we’ll use for the IP of our router on the local network.

The configuration file for dhcpd is /etc/dhcp/dhcpd.conf. You can configure it as follows for our purposes:

default-lease-time 600;
max-lease-time 7200;

subnet netmask {
        option domain-name-servers;
        option routers;


This will hand out IP addresses between and for your local network. When/if they run out, old addresses will be reused.

Step 3 – Configure bind9 to provide DNS for your network

Debian uses /etc/bind for its bind9 named configuration files. The one we care about in this case is /etc/bind/named.conf.options

At some point the file will contain the directive allow-recursion, inside the options block. The act of allowing a DNS server to provide DNS for domains other than ones it hosts is referred to as recursion, as it is recursively contacting other DNS servers to carry out the client’s request. Allow recursion for your local network as follows:

allow-recursion {; };

Step 4 – Allow packet forwarding in the kernel

Make sure the following two lines are either present or not commented in /etc/sysctl.conf


Then reload sysctl:

# sysctl -p

Step 5 – iptables packet fowarding/masquerading

We need to have iptables route packets from eth0 to eth1. For this we will use an init script. Create this file: /etc/init.d/iptables


# Provides: iptablesrules
# Required-Start:
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description:
# Description:

iptables -F
iptables -t nat -F

iptables -P INPUT ACCEPT

iptables -A FORWARD -i eth1 -s -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

The most important lines are the last two. The first is accepting all packets that forward from eth1 (the local network) and the second masquerades them out eth0 (the internet).

That big comment at the top is to avoid warnings from Debian’s new dependency boot system.

Now enable the script:

# update-rc.d iptables enable

Step 6 – Restart services (or reboot)

/etc/init.d/bind9 restart
/etc/init.d/isc-dhcp-server restart


At this point, you’re essentially done. Restart the services and your machines on your local network will start receiving IP addresses and be able to connect to the internet, faster than if you were using a normal consumer-grade router.

Read on if you’d like more functionality.

Appendix 0 – Port forwarding

As tempting as hosting all the services you want on your router may be, you will invariably want to forward ports to machines behind your router.  Simply add this line to the iptables init script we made:

iptables -t nat -I PREROUTING -p tcp --dport 2080 -i eth0 -j DNAT --to

This will forward all requests coming from eth0 (the internet) on port TCP 2080 to port 80 on machine If you need to use UDP rather than TCP, replace tcp with udp in that command.

Appendix 1 – Static IP’s on the local network

Having all of the computers on your network get a random dhcp address can be inconvenient if you want to export NFS shares to a single machine, among other reasons. DHCP can assign IP addresses based on MAC addresses. You can add lines such as the following to the dhcpd.conf file we referred to earlier:

host adore {
 hardware ethernet f4:6d:04:44:11:fc;

What you provide for the hostname can be anything you feel like making up, really. Make sure that the IP you give it does not overlap the range you are having dhcpd provide.

Appendix 2 – Well, what if I want WiFi?

A nice use for your old Linksis wifi router would be to use it as a hotspot. Simply log in to its admin interface, disable its built-in DHCP server, configure its WiFi settings as you’d prefer, and plug one of its switch ports into your switch which is connected to your Linux router. Leave the Linksys’ WAN port unplugged.

At this point it will essentially serve as a wireless “switch” of sorts. So you’ll have all the benefits of using a computer running Linux as a router, and still have WiFi for your place using the old Linksys as a hotspot.

Another way of providing WiFi connectivity is adding a wireless card to your Linux router. Unfortunately, that isn’t something I’ve felt like dealing with yet, so I’m not going to write an article on it.

Installing php-gtk on Debian

So you want to install PHP’s gtk extension. Compared to GTK’s bindings for Perl and Python, PHP’s apparently is under-maintained and is a pain to install as the developers have not accommodated changes in libtool. We will need to install various development packages, temporarily tweak libtool, and then attempt compiling PHP-GTK and enabling it, provided that didn’t fail.

This tutorial was performed on vanilla 64-bit Debian Squeeze 6.0.2 successfully. Something similar will hopefully work for Ubuntu and other Debian derivatives.

First off, become root and install these packages. We’ll be snagging the latest version via subversion and compiling it. We need pear to install cairo, which apparently is a dependency of compiling php-gtk

Assuming you use sudo like myself, you’ll use sudo -i to drop yourself to a root shell. If you have the root account enabled, either log in as root directly or use su - as a normal user to become root.

apt-get install build-essential php5-cli php5-dev libgtk2.0-dev libglade2-dev subversion php-pear

Now get cairo via pecl

pecl install cairo-beta

Unfortunately we temporarily need to hack our libtool configuration. Don’t worry; we’ll restore the old version later. As we’re running as root, we do not need to tweak the file permissions at all here, as other tutorials seem to mention.

cd /usr/share/aclocal
cp libtool.m4 libtool.m4.bak
cat lt~obsolete.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 >> libtool.m4

Check it out, run buildconf, compile, etc. This is the most important part. If buildconf or configure do not finish successfully, undo the above change (move on to my next step) and reply demanding me to update this tutorial. Please give as much information regarding your distro’s setup and the steps you have taken as possible.

svn co php-gtk
cd php-gtk
make install

Now undo that ugly libtool hack we used:

mv /usr/share/aclocal/libtool.m4.bak /usr/share/aclocal/libtool.m4

Enable cairo and php-gtk extensions by adding the necessary lines to the php.ini for command-line. We are not creating .ini’s for each .so in the /etc/php5/conf.d/ folder (as php extensions normally do on Debian) because then php5-cgi will attempt loading them and web pages will generate error 500’s as they try to connect to X-Windows

echo '' >> /etc/php5/cli/php.ini
echo '' >> /etc/php5/cli/php.ini

Ensure that gtk is properly installed. We shouldn’t need to worry about cairo being broken since pecl shouldn’t have failed.

php -m | grep gtk

This should give something such as the following if all goes well. If it does not list php-gtk, we have failed.

root@adore:~# php -m | grep gtk

To further verify everything is working correctly, you should probably test a sample GTK hello world as described here: or just run the php-gtk software you sought this tutorial for anyway. This is unnecessary if you are installing php-gtk just to get a tool such as the Phoronix Test Suite to work.

You should be done! Comments are much appreciated!

Uninstalling php-gtk

Uninstall by killing the shared library/header files and then removing the line from the cli php.ini. (Due to your shell’s noclobber possibly being enabled, we are first outputting a gtk-less php.ini to a separate file and then moving it on top of the one including gtk)

rm -rf /usr/lib/php5/20090626/ /usr/include/php5/ext/php_gtk2/
grep -v gtk /etc/php5/cli/php.ini > orig_php.ini
mv orig_php.ini /etc/php5/cli/php.ini