<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4016193628170998370</id><updated>2012-02-16T06:07:54.883-08:00</updated><title type='text'>waf-devel</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>19</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-2450563171026192281</id><published>2012-01-28T05:12:00.000-08:00</published><updated>2012-01-28T05:12:10.446-08:00</updated><title type='text'>Escaping the Google cave</title><content type='html'>&lt;h2&gt;1. The problem with user tracking&lt;/h2&gt;A few years ago, a user complained that the Waf project was using Googlecode, and threatened to not use Waf if it remained hosted on the Google server. I thought that it was paranoid at that time, and I just forgot about that request...&lt;br /&gt;&lt;br /&gt;Now a few years have passed, and it is a bit late to move to Github. Also, tons of websites are now hosted by Google, and it would be impossible to avoid all of them. But this is not my main concern. Rather, I have taken the bad habit of logging in on my Google or Facebook accounts more often than I cleared all my cookies and I am getting targeted content too often.&lt;br /&gt;&lt;br /&gt;For instance I started to notice that it was much harder to obtain information from Google search. I would frequently find Python in all my search results. Searching for Java programming techniques would lead me to more Python sites. Searching for Scons or CMake would only lead me back to Waf. I would also get ads related to the contents of my emails. In other words, the Google tracking had started to create a convenient place where I would always find familiar information.&lt;br /&gt;&lt;br /&gt;Since I was a child, I have always had the important feeling or belief that there exists a world independent of me, a reality that is worth exploring (&lt;a href="http://en.wikipedia.org/wiki/Solipsism"&gt;solipsists&lt;/a&gt; may disagree). It is a virtue to try to know the world as it is and not as one would like it to be. The web is interesting because it gives an opportunity of getting other views easily, and to explore a world that is not limited or bound by a particular view, and I would like to keep it this way.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;2. Filtering tracking websites&lt;/h2&gt;&lt;br /&gt;First of all, I believe that the "do not track" cookie is one of the most idiotic invention created recently. If I were creating a website and if someone set that cookie, I would really love to track that someone in the sneakiest way possible. This is equivalent to wandering around with a big sign reading "kick me" stuck on your back.&lt;br /&gt;&lt;br /&gt;One of the first things I have tried is to avoid tracking by blocking the scripts that report the pages that I am visiting, for example google analytics. For this it is simple to edit the file &lt;i&gt;/etc/hosts&lt;/i&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: shell"&gt;127.0.0.1 www.google-analytics.com&lt;br /&gt;127.0.0.1 google-analytics.com&lt;br /&gt;127.0.0.1 ssl.google-analytics.com&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There are many more &lt;a href="http://http//someonewhocares.org/hosts/"&gt;addresses to exclude&lt;/a&gt; however, and it does not prevent google from reading your mail. It is enough to log in once to Googlemail to get targeted ads and personalized contents again.&lt;br /&gt;&lt;br /&gt;The filtering approach is also imperfect, for example, if it becomes widespread, a few websites will start breaking if the tracking is blocked. It will be easy to test in javascript what hosts are blocked to create a fingerprint of the user. This goes back to the principles of information theory, if you have a secret, it will leak eventually however hard you try to keep it.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;3. Setting up multiple identities&lt;/h2&gt;Trying to filter the websites is just too complicated to do, and removing http cookies, flash cookies, visited pages, website preferences and user-agent is just too much of a hassle. Websites may also try &lt;a href="http://lcamtuf.coredump.cx/cachetime/"&gt;cache timing attacks&lt;/a&gt; to get more information on you anyway.&lt;br /&gt;&lt;br /&gt;Tor is nice but limited in terms of feature and speed (no flash, use the Tor browser, etc). Virtual machines are convenient but use a lot of resources, for example flash and javascript are too slow to be usable. I keep them for untrusted websites (and with flash disabled anyway).&lt;br /&gt;&lt;br /&gt;The best success I have had so far is by setting up multiple Linux user accounts and multiple identities. I keep my current account for normal stateless activities, and use the other accounts for stateful operations. For example, I created a user account named "google" for all googlemail and googlecode-related activities:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: shell"&gt;# useradd google -p users&lt;br /&gt;# mkdir /home/google&lt;br /&gt;# echo "export DISPLAY=:0" &amp;gt;&amp;gt; /home/google/.bashrc&lt;br /&gt;# chown google /home/google/.bashrc /home/google&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The current user account must allow the windows for each other user accounts to be displayed on the current Xorg session. Make sure to &lt;b&gt;always&lt;/b&gt; use xhost +local:accountname:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: shell"&gt;echo "xhost + local:google" &amp;gt;&amp;gt; ~/.profile&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To obtain any sound, it is necessary to tweak the pulseaudio settings. First, the file /etc/pulse/default.pa must be copied to ~/.pulse/default.pa and modified to allow connections from other user accounts:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: shell"&gt;&amp;gt; diff -urN /etc/pulse/default.pa ~/.pulse/default.pa &lt;br /&gt;--- /etc/pulse/default.pa       2011-10-30 03:59:03.000000000 +0100&lt;br /&gt;+++ .pulse/default.pa   2011-12-01 00:34:34.537118644 +0100&lt;br /&gt;@@ -158,3 +158,6 @@&lt;br /&gt; ### Make some devices default&lt;br /&gt; #set-default-sink output&lt;br /&gt; #set-default-source input&lt;br /&gt;+&lt;br /&gt;+load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1&lt;br /&gt;+&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then a new file must be added to each other user account, for example /home/google/.pulse/client.conf:&lt;br /&gt;&lt;pre class="brush: shell"&gt;default-server = 127.0.0.1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;After that, a web browser can be started easily&lt;br /&gt;&lt;pre class="brush: shell"&gt;sudo su&lt;br /&gt;su - google&lt;br /&gt;firefox&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To make certain that I do not confuse the accounts (the web browser completion already helps a lot), I am also using different web browsers with different versions, with different extensions (noflash, firebug, etc), with different themes and with different language settings. For example, looking at ads in Serbian or in Russian is fun. The firefox themes (Personas) even have animations to help remember what window is what.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-2450563171026192281?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/2450563171026192281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2012/01/escaping-google-cave.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/2450563171026192281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/2450563171026192281'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2012/01/escaping-google-cave.html' title='Escaping the Google cave'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-8228690454763974927</id><published>2012-01-05T11:53:00.000-08:00</published><updated>2012-01-05T12:02:17.501-08:00</updated><title type='text'>Happy new year Debian</title><content type='html'>The &lt;a href="http://bugs.debian.org/cgi-bin/pkgreport.cgi?users=ftpmaster@debian.org;tag=waf-unpack"&gt;Debian folks&lt;/a&gt; have actually started a crusade against projects using Waf. The archives containing the Waf file are now rejected. I can of course support such a policy, after all, shipping a C file generated by Bison or Flex without the grammar source file is similar to distributing proprietary software. I do not question this.&lt;br /&gt;&lt;br /&gt;But the binary file in question is a perfectly legal python script containing additional source code in a compressed form. There is no state machine, no obfuscation of the contents, and the source is not modified. This has nothing to do with &lt;a href="http://jscompress.com/"&gt;minified javascript&lt;/a&gt; since the variable names and the code structure are not modified.&lt;br /&gt;&lt;br /&gt;It may be difficult to inspect the file in question, but then how about the 1MB configure scripts that are redistributed with most Autotool-based projects? The configure file is machine-generated, it contains fragments of original source files, and make it dead easy to conceal malware. If the policy were applied properly (ensure security and prevent machine-generated contents), then Autotool-based packages containing a configure script should be removed as well.&lt;br /&gt;&lt;br /&gt;There are very good reasons of shipping the Waf file with the projects, for example one is to provide the users with a way to discard installation and interpreter issues. This is exactly what the configure script does. Then, the &lt;a href="http://wiki.debian.org/UnpackWaf"&gt;workaround suggested&lt;/a&gt; by a Debian folk consists in unpacking the Waf file, which means that people have the choice of getting their projects removed from Debian or to cripple their packages by removing support for compilation with Python 2.5, 2.4 and potentially 2.3.&lt;br /&gt;&lt;br /&gt;Was not Debian supposed to promote and help open-source projects without making a discrimination?&lt;br /&gt;&lt;br /&gt;Or maybe it is that some people have too much time on their hands and cannot break &lt;a href="http://digitaloffense.net/tools/debian-openssl/"&gt;critical elements of the system&lt;/a&gt; anymore.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-8228690454763974927?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/8228690454763974927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2012/01/debian.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/8228690454763974927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/8228690454763974927'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2012/01/debian.html' title='Happy new year Debian'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-5067116733118701811</id><published>2011-12-25T10:23:00.000-08:00</published><updated>2011-12-25T11:18:39.633-08:00</updated><title type='text'>So, how do you get the KDE source code?</title><content type='html'>I finally found some time to start working on my personal application &lt;a href="http://code.google.com/p/semantik"&gt;Semantik&lt;/a&gt; again. I started to work on Waf a long time ago to simplify the development of KDE applications.&lt;br /&gt;&lt;br /&gt;I had not checked out the KDE website for a while, and it has apparently changed quite a lot. It was probably designed by usability experts, judging by the &lt;a href="http://www.kde.org/download/"&gt;blue-on-blue color scheme&lt;/a&gt;. This may irritate the eyes, but trap of web links will fry your brain. Here is for example the links I have followed when looking for the latest/development source code:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://www.kde.org/"&gt;Go to the main page&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.kde.org/developerplatform"&gt;KDE provides a development platform, nice&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://techbase.kde.org/Development"&gt;Ok, so here is the development platform&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://techbase.kde.org/Development/Git"&gt;No source code, need to learn git. But I know git&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://techbase.kde.org/Getting_Started/Build/KDE4"&gt;Yes, give me KDE4, this is what I want&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://techbase.kde.org/Getting_Started/Build/KDE4#Source"&gt;No source code here&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://techbase.kde.org/Getting_Started/Sources"&gt;Ok, so where can it be?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://projects.kde.org/projects/kde/kdeedu"&gt;Let's pick kde edu&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://projects.kde.org/projects/kde/kdeedu/activity"&gt;Nice looking page, but where is the source?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://techbase.kde.org/Getting_Started/Build/KDE4#Source"&gt;Let's backtrack&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://techbase.kde.org/Getting_Started/Build/kdesrc-build"&gt;Do I need this?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;The little information contained on the website is hidden very well. At this point I lost hope to get the development code and I opted for the released code. The download button is of course called "get kde software". The source code is only a few clicks away!&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://www.kde.org/download/"&gt;Download page, with a table of contents&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.kde.org/download/#v4.7"&gt;Download KDE 4.7&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.kde.org/info/4.7.4.php"&gt;Finally, the code&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://download.kde.org/download.php?url=stable/4.7.4/src/kalzium-4.7.4.tar.bz2"&gt;No, it is not over, you must select a mirror... or click the donate button!&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;The kde.org website was clearly made to maximize user clicks. The only thing it is missing at this point is ads with fake &lt;a href="http://www.youtube.com/watch?v=mGDuExhS6Nw"&gt;download&lt;/a&gt; buttons (do not click on this &lt;a href="http://www.youtube.com/watch?v=mGDuExhS6Nw"&gt;link&lt;/a&gt; by the way).&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.gnome.org"&gt;Gnome website&lt;/a&gt; is only slightly better. It reminds me of the apple website which I used when I needed a mac mini. There are lots of corporate fonts and pictures with rounded corners, so that at least I can understand that I am reading the wrong page if I am a developer. Trying to attract developers by pretending they can find &lt;a href="http://live.gnome.org/GnomeLove"&gt;love&lt;/a&gt; also had the opposite effect on me.&lt;br /&gt;&lt;br /&gt;Why cannot those developer websites imitate the design of the &lt;a href="http://www.samba.org/samba/download/"&gt;Samba website&lt;/a&gt; instead? The information is displayed clearly and features virtually no link traps.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-5067116733118701811?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/5067116733118701811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2011/12/so-how-do-you-get-kde-source-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/5067116733118701811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/5067116733118701811'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2011/12/so-how-do-you-get-kde-source-code.html' title='So, how do you get the KDE source code?'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-3631721575626020972</id><published>2011-12-17T01:03:00.000-08:00</published><updated>2011-12-17T01:03:42.874-08:00</updated><title type='text'>Python 3 is not ready for production</title><content type='html'>What do you get when you try to install python3.2.2 on Linux?&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: shell"&gt;&amp;gt; python3.2&lt;br /&gt;Could not find platform dependent libraries &amp;lt;exec_prefix&amp;gt;&lt;br /&gt;Consider setting $PYTHONHOME to &amp;lt;prefix&amp;gt;[:&amp;lt;exec_prefix&amp;gt;]&lt;br /&gt;Python 3.2.2 (default, Dec 17 2011, 10:04:46) &lt;br /&gt;[GCC 4.6.2] on linux2&lt;br /&gt;Type "help", "copyright", "credits" or "license" for more information.&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;File "/etc/pythonstart", line 5, in &amp;lt;module&amp;gt;&lt;br /&gt;import atexit&lt;br /&gt;ImportError: No module named atexit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It is the first time I am hear the PYTHONHOME variable is necessary. So what happens if we set it?&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: shell"&gt;&amp;gt; export PYTHONHOME=/usr/local/lib64/python3.2/&lt;br /&gt;&amp;gt; python3.2&lt;br /&gt;Fatal Python error: Py_Initialize: Unable to get the locale encoding&lt;br /&gt;LookupError: no codec search functions registered: can't find encoding&lt;br /&gt;Aborted&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Alright, encoding issues. Python 3 does not work on Linux anymore. Let's try to uninstall it?&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: shell"&gt;&amp;gt; sudo make uninstall&lt;br /&gt;make: *** No rule to make target `uninstall'.  Stop&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And now the broken files must be removed by hand. I guess I will wait for Python 3.2.3, after all &lt;a href="http://bugs.python.org/issue13156"&gt;threading is broken&lt;/a&gt; in both python 2.7.2 and 3.2&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-3631721575626020972?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/3631721575626020972/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2011/12/python-3-is-not-ready-for-production.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/3631721575626020972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/3631721575626020972'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2011/12/python-3-is-not-ready-for-production.html' title='Python 3 is not ready for production'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-2833861112407733031</id><published>2011-07-03T04:52:00.000-07:00</published><updated>2011-07-03T04:52:18.172-07:00</updated><title type='text'>wscript file headers</title><content type='html'>A few users have asked why the wscript files usually include the following header if they are not meant to be executed directly:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: py"&gt;#! /usr/bin/env python&lt;br /&gt;# encoding: utf-8&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Several benefits have been observed over the time, and it appears that this header is a best practice:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Most text editors - especially on unix-like systems - will read the first line beginning by &lt;b&gt;#!&lt;/b&gt; to apply proper syntax highlighting. Your text editor may well display the file properly, but others may not.&lt;/li&gt;&lt;li&gt;If the wscript files are ever meant to be executed, then:&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;The process will not hang when called as &lt;b&gt;./wscript&lt;/b&gt; (the 'import' program takes screenshots)&lt;/li&gt;   &lt;li&gt;The /usr/bin/env will redirect the interpreter to the adequate python executable (python can be installed in /usr/local or /opt for example)&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;The encoding declaration will prevent special characters such as &lt;b&gt;&amp;euro;, &amp;eacute;&lt;/b&gt; or &lt;b&gt;&amp;iacute;&lt;/b&gt; from causing errors&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;When a wscript file is created for the first time, it may have to be reloaded to force the text editor to take the file type into account. In Vim at least, a mapping can be added to save the hassle of re-opening the file:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: plain"&gt;au BufNewFile,BufRead wscript* set filetype=python&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-2833861112407733031?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/2833861112407733031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2011/07/wscript-file-headers.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/2833861112407733031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/2833861112407733031'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2011/07/wscript-file-headers.html' title='wscript file headers'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-2467680315555289029</id><published>2011-05-22T04:47:00.000-07:00</published><updated>2011-05-22T05:24:19.612-07:00</updated><title type='text'>Running Waf on different Python interpreters</title><content type='html'>&lt;a href="http://ironpython.codeplex.com/"&gt;IronPython 2.7&lt;/a&gt; now provides a subprocess module, and the good news is that Waf will be able to run on it. The changes are only in Waf trunk for now, they will be available in Waf 1.6.5 once a remaining issue is resolved (the logging module behaves differently on IronPython). &lt;br /&gt;&lt;br /&gt;&lt;style&gt;table.lay { border-collapse: collapse; }table.lay td, table.lay th { border: 1px solid black; margin: 5px;} &lt;/style&gt;&lt;br /&gt;A few of you may be curious to know how well Waf performs on different python interpreters. Different propjects may have different requirements, so the tests are always biased in one way or another. Among all the tests considered so far, the &lt;a href="http://code.google.com/p/waf/source/browse/trunk/utils/genbench.py"&gt;genbench&lt;/a&gt; script provides a good balance between project size, process execution, regexps and parsing. The numbers collected represent the best run in in five executions:&lt;br /&gt;&lt;pre&gt;./genbench.py /tmp/build 50 100 15 5&lt;br /&gt;cd /tmp/build&lt;br /&gt;waf clean; time waf build -p -j3&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;On Windows XP, the IronPython runtime is fairly close to the Pypy one. And Pypy 1.5 did not complete normally (file descriptor leak).&lt;br /&gt;&lt;br /&gt;&lt;table class="lay"&gt;&lt;caption&gt;Windows XP&lt;/caption&gt; &lt;tbody&gt;&lt;tr&gt;  &lt;th&gt;cPython 2.7&lt;/th&gt;  &lt;th&gt;IronPython 2.7&lt;/th&gt; &lt;th&gt;Pypy 1.5&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;  &lt;td&gt;1m54&lt;/td&gt;  &lt;td&gt;2m14&lt;/td&gt; &lt;td&gt;2m05&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;IronPython requires .NET 4, and it would not run on Linux using Mono 2.10.2. It is no surprize that the test completes faster as spawning new processes (fork) is slower on Windows. Pypy 1.5 could not even complete normally once in about 10 runs.&lt;br /&gt;&lt;br /&gt;&lt;table class="lay"&gt;&lt;caption&gt;Linux&lt;/caption&gt; &lt;tbody&gt;&lt;tr&gt;  &lt;th&gt;python 2.6.5&lt;/th&gt;  &lt;th&gt;python 3.2&lt;/th&gt;  &lt;th&gt;jython 2.5.2&lt;/th&gt; &lt;/tr&gt;&lt;tr&gt;  &lt;td&gt;1m41&lt;/td&gt;  &lt;td&gt;1m41&lt;/td&gt;  &lt;td&gt;5m30&lt;/td&gt;  &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;For the moment, the best interpreter remains cPython for both portability and performance.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-2467680315555289029?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/2467680315555289029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2011/05/running-waf-on-different-python.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/2467680315555289029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/2467680315555289029'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2011/05/running-waf-on-different-python.html' title='Running Waf on different Python interpreters'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-2234649627109681753</id><published>2011-04-30T03:29:00.000-07:00</published><updated>2011-04-30T03:29:09.881-07:00</updated><title type='text'>Debugging tools</title><content type='html'>Trying to trace or to debug a build almost always incurs a performance penalty. The most important tool is included by default but only enabled when calling waf with the verbose option (waf -v). Others are present in the waflib/extras folder and are not included by default. They can be added to the waf file or downloaded by calling "waf update --files=parallel_debug,why"&lt;br /&gt;&lt;br /&gt;The module &lt;a href="http://code.google.com/p/waf/source/browse/trunk/waflib/extras/why.py"&gt;"why"&lt;/a&gt; provides some more output to help understanding why files are being compiled. It requires a fresh recompilation though, and inflates the cache files significantly as it stores some data between the builds. The output will display the task signatures and the reason of the execution:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;12:26:20 /comp/waf/demos/c&gt; ./waf build --zones=task&lt;br /&gt;Waf: Entering directory `/disk/comp/waf/demos/c/build'&lt;br /&gt;12:26:21 task -&gt; Task must run                      : c3490b5e8498da72aef5a9f645d72276 39da3e173d11cdbb273cda14856dbb6a&lt;br /&gt;12:26:21 task -&gt; * Source file or manual dependency : 3d3fde4f5fc0124efdba8e94e1d216f8 5e4ef70cc1618412ef9975baab0157c1&lt;br /&gt;[12/15] c: program/main.c -&gt; build/program/main.c.1.o&lt;br /&gt;Waf: Leaving directory `/disk/comp/waf/demos/c/build'&lt;br /&gt;'build' finished successfully (0.089s)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;For performance debugging, the module &lt;a href="http://code.google.com/p/waf/source/browse/trunk/waflib/extras/parallel_debug.py"&gt;parallel_debug&lt;/a&gt; creates pictures representing when tasks are executed during the build. The diagrams show how well the build can be distributed, and therefore how fast the build can be. Generating the diagrams incurs a minor performance penalty, which is the reason why this tool is not included by default in the waf file.&lt;br /&gt;&lt;br /&gt;It has been updated recently to improve the layout, now tooltips are present in the svg output file. Follow the links to consult the diagrams of the Samba 4 developer build &lt;a href="http://www.freehackers.org/~tnagy/smb-2cpu.svg"&gt;for 2 processors&lt;/a&gt; and &lt;a href="http://www.freehackers.org/~tnagy/smb-8cpu.svg"&gt;for 8 processors&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-2234649627109681753?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/2234649627109681753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2011/04/debugging-tools.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/2234649627109681753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/2234649627109681753'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2011/04/debugging-tools.html' title='Debugging tools'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-5264948324220960246</id><published>2011-04-30T00:37:00.000-07:00</published><updated>2011-04-30T01:04:57.911-07:00</updated><title type='text'>Colors in cmd</title><content type='html'>The cmd window looks terrible compared to rxvt/xterm ones, and unlike others, cmd is unable to interpret &lt;a href="http://en.wikipedia.org/wiki/ANSI_escape_code"&gt;ANSI escape codes&lt;/a&gt;. The module &lt;a href="http://code.google.com/p/waf/source/browse/trunk/waflib/ansiterm.py"&gt;ansiterm&lt;/a&gt; has been been bringing happy colors in cmd and other consoles since &lt;a href="http://code.google.com/p/waf/issues/detail?id=243"&gt;2008&lt;/a&gt;. It wraps sys.stdout/sys.stderr in an object which intercepts the escape codes to provide the coloring by using a few functions from the windll module.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-VGRMF-aJV80/TbvBSlXiCXI/AAAAAAAACiE/-Os0SxHvces/s1600/cmdwin32_4.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="636" src="http://2.bp.blogspot.com/-VGRMF-aJV80/TbvBSlXiCXI/AAAAAAAACiE/-Os0SxHvces/s1600/cmdwin32_4.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The progress bar, which was broken for a long time, is even displayed properly (waf 1.6.4):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-FLDXRZoWrjg/TbvChgAlMNI/AAAAAAAACiU/E0x8hPQIAxo/s1600/cmdwin32_5.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="636" src="http://1.bp.blogspot.com/-FLDXRZoWrjg/TbvChgAlMNI/AAAAAAAACiU/E0x8hPQIAxo/s1600/cmdwin32_5.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The display in msys it also known to work in waf 1.6:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-Hiv7uPtXYDQ/Tbu04VqALPI/AAAAAAAAChk/058NzvoPfbw/s1600/msys-p.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" width="638" src="http://3.bp.blogspot.com/-Hiv7uPtXYDQ/Tbu04VqALPI/AAAAAAAAChk/058NzvoPfbw/s1600/msys-p.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Right now, one issue remain in &lt;a href="http://code.google.com/p/waf/issues/detail?id=931"&gt;Windows Vista&lt;/a&gt;. The platform-specific and underdocumented functions from the module windll make it very difficult to understand and fix the problems though &lt;pre&gt;windll.kernel32.FillConsoleOutputCharacterA&lt;/pre&gt;&lt;br /&gt;New python projects resembling ansiterm.py have appeared recently, here are for example:&lt;br /&gt;&lt;br /&gt;* &lt;a href="http://code.google.com/p/colorama/"&gt;Colorama&lt;/a&gt;&lt;br /&gt;* &lt;a href="http://code.google.com/p/colorconsole/"&gt;Colorconsole&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Both also split the small amount of code into several files, which make the re-use only more difficult, and neither seems to support clearing single lines, which is mandatory for displaying progress bars properly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-5264948324220960246?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/5264948324220960246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2011/04/colors-in-cmd.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/5264948324220960246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/5264948324220960246'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2011/04/colors-in-cmd.html' title='Colors in cmd'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-VGRMF-aJV80/TbvBSlXiCXI/AAAAAAAACiE/-Os0SxHvces/s72-c/cmdwin32_4.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-7638670392381986617</id><published>2011-01-08T08:50:00.000-08:00</published><updated>2011-01-10T13:24:26.958-08:00</updated><title type='text'>Python 3.2, and the build system kit</title><content type='html'>&lt;p&gt;The new &lt;a href="http://www.python.org/dev/peps/pep-3148/"&gt;&amp;quot;concurrent.futures&amp;quot; module from Python 3.2&lt;/a&gt; will now make it even easier to execute tasks concurrently. We never miss an opportunity to remove some code so we had to try it, some functionality being similar to the contents of the &lt;a href="http://code.google.com/p/waf/source/browse/trunk/waflib/Runner.py"&gt;Runner&lt;/a&gt; module.&lt;/p&gt;&lt;p&gt;First, we could not remove a much code as we hoped: fewer than 20 lines, most of the code being in the synchronization and the exception handling anyway. Then we met &lt;a href="http://www.freehackers.org/~tnagy/runtime_futures.png"&gt;a surprising performance degradation&lt;/a&gt; linked to the creation of &lt;a href="http://mail.python.org/pipermail/python-dev/2010-December/106670.html"&gt;circular references&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Finally, the Python executor appeared to increase the builds by a few seconds on our build benchmarks, so we finally gave up.&lt;/p&gt;&lt;p&gt;The executor API looks good though, and many developers will be tempted to try to create new python-based build systems from it. Executing tasks represents only a very small part of what one expects in a build system though:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A system for handling commands and command-line options&lt;/li&gt;&lt;li&gt;A system of (task) order and dependencies&lt;/li&gt;&lt;li&gt;A handler for exceptions and user errors&lt;/li&gt;&lt;li&gt;A usable system (a very difficult problem)&lt;/li&gt;&lt;li&gt;An extension system for new programming languages&lt;/li&gt;&lt;li&gt;A portable system (not limited to Python 3.2)&lt;/li&gt;&lt;li&gt;Adequate performance (it is so easy to over synchronize or to write bad algorithms)&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;Developers seem to underestimate the amount of work required to make a system work for more than one or two projects (Waf has had nearly 11000 revisions in 6 years). Specialized and incomplete build scripts are still popping up. Just to name a few python-based ones:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.blueskyonmars.com/2009/01/28/paver-10a1-is-out/"&gt;Paver&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://agendaless.com/Members/chrism/software/buildit/"&gt;Buildit&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/erickt/fbuild"&gt;Fbuild&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/fabricate/"&gt;Fabricate&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=241209"&gt;Tutorials...&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;The fragmentation seems unavoidable, and the situation is probably going to be similar to that of operating systems or programming languages, with a few big players and tons of niche projects.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;If it must happen, then let it happen properly, at least. Starting in &lt;a href="http://waf.googlecode.com/files/waf-1.6.2.tar.bz2"&gt;version 1.6.2&lt;/a&gt;, the Waf framework features a new &lt;b&gt;build system kit&lt;/b&gt; which enables the creation of new build systems. By re-using the tested and maintained components from the Waf framework, much more time can be spent on more interesting problems such as creating an intuitive XML/YAML/JSON schema (if you believe that IDEs should edit your scripts) or creating a domain-specific programming language (make-like, cmake-like, ... ?), or extracting commands and dependencies to create derivated files (Makefiles, Visual studio, ...)&lt;/p&gt;&lt;p&gt;The &lt;a href="http://code.google.com/p/waf/source/browse/trunk/build_system_kit/"&gt;few examples&lt;/a&gt; illustrate the possibilities offered by the Waf framework:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/waf/source/browse/trunk/build_system_kit/overview"&gt;overview&lt;/a&gt;:        Create a file using the Waf components to perform simple builds that do not use wscript files&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/waf/source/browse/trunk/build_system_kit/parser"&gt;parser&lt;/a&gt;:          Add a parser for a domain-specific language, and create a file able to build targets from specific files&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/waf/source/browse/trunk/build_system_kit/noscript"&gt;noscript&lt;/a&gt;:        Create a file able to build targets without using a script file, finding the source files from header dependencies&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/waf/source/browse/trunk/build_system_kit/nostate/"&gt;nostate&lt;/a&gt;:         Create a make-like build system that does not use build files (timestamps only)&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/waf/source/browse/trunk/build_system_kit/makefile_dumper/"&gt;makefile_dumper&lt;/a&gt;: Use the Waf API to dump the build decription into a makefile&lt;/li&gt;&lt;/ul&gt;Have a look and think &lt;a href="http://cuteoverload.com/tag/kittens/"&gt;of the kittens&lt;/a&gt; before trying to start a build system from scratch.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-7638670392381986617?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/7638670392381986617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2011/01/python-32-and-build-system-kit.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/7638670392381986617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/7638670392381986617'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2011/01/python-32-and-build-system-kit.html' title='Python 3.2, and the build system kit'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-1682313855317628738</id><published>2010-12-05T10:11:00.000-08:00</published><updated>2010-12-20T04:37:37.943-08:00</updated><title type='text'>Make your own build system with the Waf framework</title><content type='html'>Are you dissatisfied with Python? Do you prefer XML, YAML or JSON for build scripts? Or maybe you think you can create a better domain-specific language for build scripts?&amp;nbsp;Before trying to invent new build system from scratch, try re-using the Waf framework.&lt;br /&gt;&lt;br /&gt;Waf 1.6 features a new customization system for the Waf files, which means that the Waf libraries can be re-used easily without forcing the use of wscript files. Here is how to create a waf file that will print "Hello, world!" and stop:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: plain"&gt;waf configure &lt;br /&gt;  --prelude=$'\tprint("Hello, world!")\n\tsys.exit(0)\n'&lt;br /&gt;&lt;/pre&gt;The resulting waf file will then exhibit the following lines of code:&lt;br /&gt;&lt;pre class="brush: py"&gt;if __name__ == '__main__':&lt;br /&gt;    print("Hello, world!")&lt;br /&gt;    sys.exit(0)&lt;br /&gt;    from waflib import Scripting&lt;br /&gt;    Scripting.waf_entry_point(cwd, VERSION, wafdir)&lt;br /&gt;&lt;/pre&gt;Writing code in the &lt;i&gt;prelude&lt;/i&gt; section is a bit complicated, but the execution can be delegated to a separate waf tool. For example, with a tool named &lt;b&gt;bbdlib&lt;/b&gt; featuring a function named "start":&lt;br /&gt;&lt;pre class="brush: plain"&gt;./waf-light configure build  --tools=$PWD/bbdlib.py &lt;br /&gt;  --prelude=$'\tfrom waflib.extras import bbdlib\n\tbbdlib.start(cwd, VERSION, wafdir)\n\tsys.exit(0)'&lt;br /&gt;&lt;/pre&gt;The file &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;bbdlib.py&lt;/span&gt; will be included in the resulting waf file as &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;waflib/extras/bbdlib.py&lt;/span&gt;, so the resulting code has to use an import. Also, the original parameters (current working directory, waf version and waf directory) are propagated as they can be useful in the execution:&lt;br /&gt;&lt;pre class="brush: py"&gt;if __name__ == '__main__':&lt;br /&gt;    from waflib.extras import bbdlib&lt;br /&gt;    bbdlib.start(cwd, VERSION, wafdir)&lt;br /&gt;    sys.exit(0)&lt;br /&gt;    from waflib import Scripting&lt;br /&gt;    Scripting.waf_entry_point(cwd, VERSION, wafdir)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here is for example a script that may be used to read files named "bbit":&lt;br /&gt;&lt;pre class="brush: py"&gt;import os, sys, imp&lt;br /&gt;from waflib import Context, Options, Configure, Utils, Logs&lt;br /&gt;&lt;br /&gt;def start(cwd, version, wafdir):&lt;br /&gt;    try:&lt;br /&gt;        os.stat(cwd + '/bbit')&lt;br /&gt;    except:&lt;br /&gt;        print('call from a folder containing "bbit"')&lt;br /&gt;        sys.exit(1)&lt;br /&gt;&lt;br /&gt;    Logs.init_log()&lt;br /&gt;    Context.waf_dir = wafdir&lt;br /&gt;    Context.top_dir = Context.run_dir = cwd&lt;br /&gt;    Context.out_dir = os.path.join(cwd, 'build')&lt;br /&gt;    Context.g_module = imp.new_module('wscript')&lt;br /&gt;    Context.g_module.root_path = os.path.join(cwd, 'bbit')&lt;br /&gt;    Context.Context.recurse = lambda x, y: getattr(&lt;br /&gt;         Context.g_module, x.cmd, Utils.nada)(x)&lt;br /&gt;&lt;br /&gt;    Context.g_module.configure = lambda ctx: ctx.load('g++')&lt;br /&gt;    Context.g_module.build = lambda bld: bld.objects(&lt;br /&gt;        source='main.c')&lt;br /&gt;&lt;br /&gt;    opt = Options.OptionsContext().execute()&lt;br /&gt;&lt;br /&gt;    do_config = 'configure' in sys.argv&lt;br /&gt;    try:&lt;br /&gt;        os.stat(cwd + '/build')&lt;br /&gt;    except:&lt;br /&gt;        do_config = True&lt;br /&gt;    if do_config:&lt;br /&gt;        Context.create_context('configure').execute()&lt;br /&gt;&lt;br /&gt;    if 'clean' in sys.argv:&lt;br /&gt;        Context.create_context('clean').execute()&lt;br /&gt;    if 'build' in sys.argv:&lt;br /&gt;        Context.create_context('build').execute()&lt;br /&gt;&lt;/pre&gt;Here are a few points to keep in mind:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A module simulating a wscript file is created dynamically to simulate the execution of a top-level wscript file. This script attempts to re-use as much code as possible, but some &lt;a href="http://waf.googlecode.com/svn/docs/apidocs/tools/c_config.html#waflib.Tools.c_config.run_c_code"&gt;configuration tests illustrate how to bypass all restrictions&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Although a few variables are shared by several classes (Context.top_dir), the initialization is not required. One might want to subclass the &lt;b&gt;BuildContext&lt;/b&gt; class and start with a nearly empty script.&lt;/li&gt;&lt;li&gt;The commands &lt;i&gt;configure&lt;/i&gt;, &lt;i&gt;clean&lt;/i&gt; and &lt;i&gt;build&lt;/i&gt; are implemented for the illustration. In practice it may be easier to create command subclasses for specific purposes.&lt;/li&gt;&lt;/ul&gt;The complete code source for this example can be found in the &lt;a href="http://code.google.com/p/waf/source/browse/trunk/build_system_kit/overview/"&gt;custom build section of the waf source distribution&lt;/a&gt;. If you start writing a Waf-based build system, feel free to notify us in the comments!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-1682313855317628738?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/1682313855317628738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2010/12/make-your-own-build-system-with-waf.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/1682313855317628738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/1682313855317628738'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2010/12/make-your-own-build-system-with-waf.html' title='Make your own build system with the Waf framework'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-672117700394130499</id><published>2010-12-05T06:35:00.000-08:00</published><updated>2010-12-05T10:20:25.641-08:00</updated><title type='text'>Top-level source files</title><content type='html'>A really weird scenario was discussed on IRC recently: declare a C++ program by referencing &lt;b&gt;only&lt;/b&gt; the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;main.cpp&lt;/span&gt; file, and have the build system add other source files by looking at the includes. For example:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;main.cpp&lt;/span&gt; includes &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;foo.h&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;foo.h&lt;/span&gt; has a corresponding &lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;foo.cpp&lt;/span&gt; &lt;/span&gt;file&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;foo.cpp&lt;/span&gt; includes a &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;bar.h&lt;/span&gt; file&lt;/li&gt;&lt;li&gt;the file &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;bar.h&lt;/span&gt; has a corresponding&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt; bar.cpp&lt;/span&gt; file&lt;/li&gt;&lt;/ul&gt;The program to be built declares&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;main.cpp&lt;/span&gt;&amp;nbsp;as unique source file, but the build system must detect and add the files &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;foo.cpp&lt;/span&gt; and&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;bar.cpp&lt;/span&gt;&lt;/span&gt; automatically.&lt;br /&gt;&lt;br /&gt;The request was a bit surprising, because in large projects it is usually the norm to declare the source files explicitly to avoid confusing other developers. Even &lt;a href="http://waf.googlecode.com/svn/docs/apidocs/Node.html#waflib.Node.Node.ant_glob"&gt;globs&lt;/a&gt;&amp;nbsp;are used rarely in practice, as they conceal the exact source files to use.&lt;br /&gt;&lt;br /&gt;For a single developer working on his project it probably does not matter anyhow, so an example was added in the playground area. Here is the&amp;nbsp;&lt;a href="http://code.google.com/p/waf/source/browse/trunk/playground/dynamic_recursive_tasks/wscript"&gt;link&lt;/a&gt;&amp;nbsp;to the example.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-672117700394130499?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/672117700394130499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2010/12/top-level-source-files.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/672117700394130499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/672117700394130499'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2010/12/top-level-source-files.html' title='Top-level source files'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-3635872138656900590</id><published>2010-11-25T04:54:00.000-08:00</published><updated>2010-11-25T04:54:29.934-08:00</updated><title type='text'>Code generators and unknown files</title><content type='html'>Code generators may lead to complicated scenarios, especially when they create files which are not known in advance. The usual process consists in adding&amp;nbsp;&lt;a href="http://code.google.com/p/waf/source/browse/trunk/docs/book/examples/scenarios_unknown/mytool.py"&gt;specific task classes&lt;/a&gt;&amp;nbsp;which will read the files after the execution, create the&amp;nbsp;corresponding&amp;nbsp;&lt;a href="http://waf.googlecode.com/svn/docs/apidocs/Node.html#waflib.Node.Node"&gt;node objects&lt;/a&gt;,&amp;nbsp;and update the &lt;a href="http://waf.googlecode.com/svn/docs/apidocs/Node.html#waflib.Node.Node.get_bld_sig"&gt;node signatures&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;When the&amp;nbsp;&lt;b&gt;generated files are kept in the source directory&lt;/b&gt; (and redistributed with the source code), a more simple (and less correct) solution is still possible. In the following example, a code generator will create C files in the folder named "&lt;i&gt;generated&lt;/i&gt;":&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: py"&gt;def options(opt):&lt;br /&gt;    opt.load('compiler_c')&lt;br /&gt;def configure(cnf):&lt;br /&gt;    cnf.load('compiler_c')&lt;br /&gt;def build(bld):&lt;br /&gt;    from waflib import Build&lt;br /&gt;    bld.post_mode = Build.POST_LAZY&lt;br /&gt;&lt;br /&gt;    def create_files(tsk):&lt;br /&gt;        out = tsk.generator.path.make_node('generated')&lt;br /&gt;        from waflib import Utils&lt;br /&gt;        for x in out.ant_glob('*.c'):&lt;br /&gt;            x.delete()&lt;br /&gt;        import random&lt;br /&gt;        for x in range(2):&lt;br /&gt;            num = random.randint(0, 2**31)&lt;br /&gt;            k = out.make_node('test%d.c' % num)&lt;br /&gt;            k.write('int k%d = %d;' % (num, num))&lt;br /&gt;    bld(rule=create_files, source='wscript', name='codegen')&lt;br /&gt;&lt;br /&gt;    bld.add_group()&lt;br /&gt;&lt;br /&gt;    bld.program(features='find_them',&lt;br /&gt;          source=['main.c'], target='app')&lt;br /&gt;&lt;br /&gt;from waflib.TaskGen import feature, before&lt;br /&gt;from waflib import Utils&lt;br /&gt;@feature('find_them')&lt;br /&gt;@before('process_source')&lt;br /&gt;def list_the_source_files(self):&lt;br /&gt;    self.source = Utils.to_list(self.source) +&lt;br /&gt;         self.path.ant_glob('generated/*.c')&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;The first rule&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;create_files&amp;nbsp;&lt;/span&gt;will remove any C file from the generated directory, and add new ones with random names.&amp;nbsp;The generated files, and&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;main.c&lt;/span&gt;&lt;/span&gt;&amp;nbsp;will be compiled into a program, but only after the files are correctly created.&lt;br /&gt;&lt;br /&gt;The &lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;POST_LAZY&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&lt;a href="http://waf.googlecode.com/svn/docs/wafbook/single.html#_task_execution"&gt;scheme&lt;/a&gt; will force&amp;nbsp;the &lt;a href="http://waf.googlecode.com/svn/docs/apidocs/Build.html#waflib.Build.BuildContext.groups"&gt;build groups&lt;/a&gt;&amp;nbsp;to be processed sequentially, so the total of tasks to execute will be incorrect. For example, the progress bar will reach &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;100%&lt;/span&gt;&lt;/span&gt; each time a build group is processed. For example, the task counter will jump from 1 to 5:&lt;br /&gt;&lt;br /&gt;&lt;pre class='brush: plain'&gt;12:52:14 /playground/codegen&gt; waf clean build&lt;br /&gt;'clean' finished successfully (0.005s)&lt;br /&gt;Waf: Entering directory `/playground/codegen/build'&lt;br /&gt;[1/1] codegen: wscript&lt;br /&gt;[2/5] c: main.c -&gt; build/main.c.1.o                                                                                                                                             &lt;br /&gt;[3/5] c: generated/test2017594948.c -&gt; build/generated/test2017594948.c.1.o                                                                                                     &lt;br /&gt;[4/5] c: generated/test277184706.c -&gt; build/generated/test277184706.c.1.o                                                                                                       &lt;br /&gt;[5/5] cprogram: build/main.c.1.o build/generated/test2017594948.c.1.o build/generated/test277184706.c.1.o -&gt; build/app                                                          &lt;br /&gt;Waf: Leaving directory `/playground/codegen/build'                                                                                                                &lt;br /&gt;'build' finished successfully (0.235s)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The feature&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;find_them&lt;/span&gt;&amp;nbsp;is will complete the program source list after code generator is executed, as adding &amp;nbsp;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;source=bld.ant_glob('**/*.c')&lt;/span&gt;&lt;/span&gt; would only read old files.&lt;br /&gt;&lt;br /&gt;The code source for this example has been added to &lt;a href="http://code.google.com/p/waf/source/browse/trunk/playground/codegen/wscript"&gt;the playground folder.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-3635872138656900590?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/3635872138656900590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2010/11/code-generators-and-unknown-files.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/3635872138656900590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/3635872138656900590'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2010/11/code-generators-and-unknown-files.html' title='Code generators and unknown files'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-918991435814711487</id><published>2010-09-23T11:43:00.000-07:00</published><updated>2010-09-23T12:01:56.141-07:00</updated><title type='text'>Order in archive and compression ratio (2)</title><content type='html'>&lt;div style="text-align: left;"&gt;This is a follow-up on the &lt;a href="http://waf-devel.blogspot.com/2010/09/file-order-and-compression-ratio.html"&gt;previous entry &lt;/a&gt;on observing the results of changing the file order when creating compressed archives. Shuffling the files before adding them to the archive and compressing will give files of different sizes. The following diagrams represent the distributions of the file sizes after creating 560000 archives randomly.&lt;br /&gt;&lt;br /&gt;The distribution for tar.gz files seems to follow a normal law. On this test, the gap between the smallest file and the biggest file is about 4%:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_X6wWxhs5yZw/TJuGbX3m-fI/AAAAAAAACZA/SrEMki_ln7Q/s1600/size_gzip_4.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5520153573094521330" src="http://1.bp.blogspot.com/_X6wWxhs5yZw/TJuGbX3m-fI/AAAAAAAACZA/SrEMki_ln7Q/s320/size_gzip_4.png" style="cursor: hand; cursor: pointer; display: block; height: 240px; margin: 0px auto 10px; text-align: center; width: 320px;" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The distribution for bzip2 files is dependent on the input files. Different files will produce different curves. Also, the gap between the smallest and biggest files was found to be less than 0.5%:&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="-webkit-text-decorations-in-effect: underline; color: #0000ee;"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5520153729922347842" src="http://1.bp.blogspot.com/_X6wWxhs5yZw/TJuGkgGRs0I/AAAAAAAACZI/lCo14vLdcws/s320/size_bzip2_4.png" style="cursor: pointer; display: block; height: 240px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 320px;" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="-webkit-text-decorations-in-effect: underline;"&gt;The amount of bytes of the files compressed using&amp;nbsp;&lt;a href="http://tukaani.org/xz/"&gt;xz&lt;/a&gt;&amp;nbsp;(tar cJvf) is an even number (69700, 69702,&amp;nbsp;&lt;/span&gt;69704, ...). This is causing the discontinuity in the following curve (and the optical illusion). Also, the gap between the smallest and biggest files was more than 0.9%.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="-webkit-text-decorations-in-effect: underline; color: #0000ee;"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5520154094814550450" src="http://2.bp.blogspot.com/_X6wWxhs5yZw/TJuG5vbW2bI/AAAAAAAACZQ/JUpwTBlEhOU/s320/size_xz_4.png" style="cursor: pointer; display: block; height: 240px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 320px;" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Changing the file order in the archive does change the size of the compressed archives, but the question that comes naturally is "by how much?". The amount of files and the compression speed make it a bit difficult to perform an exhaustive search (67!). To make a oneself a better idea of the bounds, using a local search such as &lt;a href="http://code.google.com/p/waf/source/browse/trunk/playground/compress/optim.py"&gt;simple hill-climbing search&lt;/a&gt;&amp;nbsp;is therefore a good idea. Here are the results after compressing about 50000 files:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;table class="lay"&gt;&lt;tbody&gt;&lt;/tbody&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;gzip&lt;/td&gt;&lt;td&gt;&lt;a href="http://freehackers.org/~tnagy/bounds_compress/best_min.tar.gz"&gt;78868&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://freehackers.org/~tnagy/bounds_compress/best_max.tar.gz"&gt;86856&lt;/a&gt;&lt;/td&gt;&lt;td&gt;10%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;bzip2&lt;/td&gt;&lt;td&gt;&lt;a href="http://freehackers.org/~tnagy/bounds_compress/best_min.tar.bz2"&gt;69818&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://freehackers.org/~tnagy/bounds_compress/best_max.tar.bz2"&gt;70227&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.5%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;xz&lt;/td&gt;&lt;td&gt;&lt;a href="http://freehackers.org/~tnagy/bounds_compress/best_min.tar.xz"&gt;68876&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="http://freehackers.org/~tnagy/bounds_compress/best_max.tar.xz"&gt;70248&lt;/a&gt;&lt;/td&gt;&lt;td&gt;2%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;tbody&gt;&lt;/tbody&gt;&lt;thead&gt;&lt;tr&gt;  &lt;th&gt;Algorithm&lt;/th&gt;  &lt;th&gt;Min size&lt;/th&gt;  &lt;th&gt;Max size&lt;/th&gt;  &lt;th&gt;Gap&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;On the bzip2 search, the hill climbing search did not increase the bounds substantially. This suggests that the search got trapped in local minimums, which is not really surprizing given the shape of the distribution. Since Waf uses bzip2 compression, it will be interesting to try another kind of local search to improve the bounds, and try to understand what makes some archives more compressible than others.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-918991435814711487?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/918991435814711487/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2010/09/order-in-archive-and-compression-ratio.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/918991435814711487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/918991435814711487'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2010/09/order-in-archive-and-compression-ratio.html' title='Order in archive and compression ratio (2)'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_X6wWxhs5yZw/TJuGbX3m-fI/AAAAAAAACZA/SrEMki_ln7Q/s72-c/size_gzip_4.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-8489224003008510112</id><published>2010-09-09T12:54:00.000-07:00</published><updated>2010-09-23T12:01:03.407-07:00</updated><title type='text'>Order in archive and compression ratio (1)</title><content type='html'>&lt;div style="text-align: left;"&gt;The &lt;a href="http://code.google.com/p/waf/source/browse/trunk/playground/compress/wscript"&gt;following example&lt;/a&gt; was recently added to the Waf directory to experiment with lots of tasks created by &lt;a href="http://freehackers.org/~tnagy/wafbook160p2/index.html#_rule_based_task_generators_make_like"&gt;make-like rules&lt;/a&gt;. The tasks from the example will perform the following operations:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Create compressed archives from the same files taken in random order (shuffled)&lt;/li&gt;&lt;li&gt;Measure the compressed file sizes,  and add the values into a main data file&lt;/li&gt;&lt;li&gt;Compute the file size distribution from the main data file&lt;/li&gt;&lt;li&gt;Create a &lt;a href="http://www.gnuplot.info/"&gt;gnuplot&lt;/a&gt; script to represent the distribution&lt;/li&gt;&lt;li&gt;Use the gnuplot script to create pictures&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;The files used in the example are the python files from Waf, and the archives are created in the tar format, which are compressed by &lt;a href="http://www.gzip.org/"&gt;gzip&lt;/a&gt; or &lt;a href="http://www.bzip.org/"&gt;bzip2&lt;/a&gt;. After creating a bit more than 300000 compressed files, the distribution of the gzip files will look like the following:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_X6wWxhs5yZw/TIlIjYcmPFI/AAAAAAAACY4/izHPQRjjwDU/s1600/size_gzip_4.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5515018991386901586" src="http://3.bp.blogspot.com/_X6wWxhs5yZw/TIlIjYcmPFI/AAAAAAAACY4/izHPQRjjwDU/s320/size_gzip_4.png" style="cursor: pointer; display: block; height: 240px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 320px;" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The file sizes range from 80282 bytes to 83605 bytes. A significant file reduction can then be obtained by carefully changing the input file order.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For the same number of compressed files, the distribution of the bzip2 files will be the following:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://1.bp.blogspot.com/_X6wWxhs5yZw/TIlGRkvbioI/AAAAAAAACYw/pgIRzx2UCqo/s1600/size_bzip2_4.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5515016486426217090" src="http://1.bp.blogspot.com/_X6wWxhs5yZw/TIlGRkvbioI/AAAAAAAACYw/pgIRzx2UCqo/s320/size_bzip2_4.png" style="cursor: pointer; display: block; height: 240px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 320px;" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The files created range from 68532 to 68807 bytes, so the size variation is not significant in this example. Yet, the shape of the distribution is much more interesting, and its causes remain mysterious.  For example, the same shape may be obtained by compressing the concatenation of the file contents, so the tar file format can be discarded. Also, the distribution curve keeps its shape by adding more data points.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Have a try yourself &lt;a href="http://code.google.com/p/waf/source/checkout"&gt;by downloading waf 1.6 from trunk&lt;/a&gt; and the &lt;a href="http://code.google.com/p/waf/source/browse/trunk/playground/compress/wscript"&gt;example&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-8489224003008510112?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/8489224003008510112/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2010/09/file-order-and-compression-ratio.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/8489224003008510112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/8489224003008510112'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2010/09/file-order-and-compression-ratio.html' title='Order in archive and compression ratio (1)'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_X6wWxhs5yZw/TIlIjYcmPFI/AAAAAAAACY4/izHPQRjjwDU/s72-c/size_gzip_4.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-1193629176791042095</id><published>2010-02-09T15:56:00.000-08:00</published><updated>2010-02-09T16:01:31.829-08:00</updated><title type='text'>Dia cannot say 'Yes'</title><content type='html'>I have been using &lt;a href="http://live.gnome.org/Dia"&gt;Dia&lt;/a&gt; for some time to create diagrams for the &lt;a href="http://freehackers.org/~tnagy/wafbook/single.html"&gt;Waf book&lt;/a&gt;. After all these years, it seems that Dia still cannot say "Yes":&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_X6wWxhs5yZw/S3H28JLQXDI/AAAAAAAAB1U/u2z0mii2Q_c/s1600-h/source.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 183px;" src="http://4.bp.blogspot.com/_X6wWxhs5yZw/S3H28JLQXDI/AAAAAAAAB1U/u2z0mii2Q_c/s320/source.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5436397738328611890" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-1193629176791042095?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/1193629176791042095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2010/02/dia-cannot-say-yes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/1193629176791042095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/1193629176791042095'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2010/02/dia-cannot-say-yes.html' title='Dia cannot say &apos;Yes&apos;'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_X6wWxhs5yZw/S3H28JLQXDI/AAAAAAAAB1U/u2z0mii2Q_c/s72-c/source.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-1780949364937081049</id><published>2010-02-02T11:41:00.000-08:00</published><updated>2010-02-02T13:22:56.199-08:00</updated><title type='text'>Single file Python apps</title><content type='html'>Various applications exist to ease software redistribution and packaging, for example:&lt;br /&gt;&lt;a href="http://klik.atekon.de/"&gt;klik&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.cpan.org/"&gt;cpan&lt;/a&gt;&lt;br /&gt;&lt;a href="http://peak.telecommunity.com/DevCenter/EasyInstall"&gt;easyinstall&lt;/a&gt;&lt;br /&gt;&lt;a href="http://rubyforge.org/projects/rubygems/"&gt;gems&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Yet, redistribution is even easier when the application is platform-independent (scripts) and when the application is directly executable.&lt;br /&gt;&lt;br /&gt;A naive approach for Python software is to concatenate all the dependent scripts into a single scripts. In the case of Waf, the tools are actually plugins which are not meant to be loaded all at once. Also, the resulting script would have a pretty huge size.&lt;br /&gt;&lt;br /&gt;The best idea so far is to create an archive (in the &lt;a href="http://www.gnu.org/software/tar/"&gt;tar file format&lt;/a&gt;) and to encode it as a base64 string hidden into the final script. The script, containing only a few routines for decompressing the archive would decode the string and unpack the library into a hidden folder when executed. All the program logic would then follow from the library files uncompressed.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.faqs.org/rfcs/rfc3548.html"&gt;base64 encoding&lt;/a&gt; is safe in the sense that any binary string as input will be transformed in a string containing only letters and a few symbols (64 in total). Yet this operation increases the file size by about 33%.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://code.google.com/p/waf/source/browse/trunk/wscript?r=3000#57"&gt;ascii85 encoding&lt;/a&gt; (used in pdf and postscript files) produces less safe symbols such as quotes and backslashes (85 characters in total), with a better cost (25%) and &lt;a href="http://code.google.com/p/waf/source/browse/trunk/waf-light?r=3000#46"&gt;only a few more lines of python code&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The best of all encodings is to avoid having to encode the binary stream at all, but the python interpreter would not accept such files. The cPython interpreter at least ignores all characters located in comments between &lt;span style="font-weight: bold;"&gt;#&lt;/span&gt; and the following newline (&lt;span style="font-weight: bold;"&gt;\n&lt;/span&gt; and &lt;span style="font-weight: bold;"&gt;\r&lt;/span&gt;), which enables us to store binary data in commented lines. By using this system, the size increase for the binary data is &lt;span style="font-weight: bold;"&gt;about 2%.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The system for the &lt;a href="http://code.google.com/p/waf/source/browse/trunk/wscript#197"&gt;waf coding&lt;/a&gt; is therefore:&lt;br /&gt;1. make a compressed archive of all the files and obtain a binary string&lt;br /&gt;2. &lt;a href="http://code.google.com/p/waf/source/browse/trunk/wscript#256"&gt;find suitable 2-character escape sequences&lt;/a&gt; for the newline characters by scanning the binary string&lt;br /&gt;3.&lt;a href="http://code.google.com/p/waf/source/browse/trunk/wscript#271"&gt; replace the forbidden characters&lt;/a&gt; by the escape sequences&lt;br /&gt;4. store the escape sequences, and write the binary string in a commented line&lt;br /&gt;&lt;br /&gt;Upon execution, the library will be unpacked by following these steps:&lt;br /&gt;1. &lt;a href="http://code.google.com/p/waf/source/browse/trunk/waf-light#61"&gt;open the script being executed,&lt;/a&gt; and read the binary string&lt;br /&gt;2. &lt;a href="http://code.google.com/p/waf/source/browse/trunk/waf-light#73"&gt;replace the escape sequences&lt;/a&gt; by the newline characters&lt;br /&gt;3. &lt;a href="http://code.google.com/p/waf/source/browse/trunk/waf-light#91"&gt;unpack the files from the binary string&lt;/a&gt; to obtain the library&lt;br /&gt;&lt;br /&gt;In the case of Jython, the interpreter is a bit different, and will first read the whole file before parsing the Python code (the parser &lt;a href="http://www.antlr.org/"&gt;used by Jython&lt;/a&gt; seems to require that). Jython will then validate the characters present in the comment sections and throw a syntax error when trying to execute the Waf file.&lt;br /&gt;&lt;br /&gt;Fortunately, &lt;a href="http://code.google.com/p/waf/source/diff?spec=svn7055&amp;amp;r=7055&amp;amp;format=side&amp;amp;path=/trunk/waf-light"&gt;changing the encoding declaration&lt;/a&gt; from '&lt;span style="font-style: italic;"&gt;utf-8&lt;/span&gt;' to '&lt;span style="font-style: italic;"&gt;iso8859-1&lt;/span&gt;' solved the problem entirely. While quite a few &lt;a href="http://www.ietf.org/rfc/rfc2279.txt"&gt;character sequences are forbidden&lt;/a&gt; in '&lt;span style="font-style: italic;"&gt;utf-8&lt;/span&gt;', binary data &lt;a href="http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html"&gt;makes no such problem&lt;/a&gt; in '&lt;span style="font-style: italic;"&gt;iso8859-1&lt;/span&gt;'.&lt;br /&gt;&lt;br /&gt;The last problem in Jython is the &lt;a href="http://bugs.jython.org/issue1445"&gt;lack of bzip2 support&lt;/a&gt;. For now to obtain a compatible waf script, it is necessary to build Waf by using the gzip compression algorithm:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;./waf-light --make-waf --zip-type=gz&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Although the waf directory is only for preparing the Waf files, replacing the contents of the folder wafadmin and changing the name of the final application may help building and redistributing other Python applications as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-1780949364937081049?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/1780949364937081049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2010/02/storing-binary-data-in-python-files.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/1780949364937081049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/1780949364937081049'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2010/02/storing-binary-data-in-python-files.html' title='Single file Python apps'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-2624366279957932890</id><published>2009-07-13T07:43:00.000-07:00</published><updated>2010-11-25T04:57:51.699-08:00</updated><title type='text'>Eclipse password recovery (cvs, subversion, ..)</title><content type='html'>Eclipse stores all the passwords under a file named .keyring, and it makes somewhat difficult to recover them.&lt;br /&gt;&lt;br /&gt;Or at least, it only seems difficult to do so. Using a plugin to enable &lt;a href="http://beanshell.org/"&gt;beanshell &lt;/a&gt;code execution such as &lt;a href="http://eclipse-shell.sourceforge.net/"&gt;Eclipse-shell&lt;/a&gt;,  the information may be recovered easily in a few lines of code:&lt;br /&gt;&lt;br /&gt;&lt;pre class='brush: java'&gt;import org.eclipse.core.internal.runtime.auth.AuthorizationDatabase;&lt;br /&gt;import java.lang.reflect.Field;&lt;br /&gt;import java.io.File;&lt;br /&gt;&lt;br /&gt;File file = new File("c:/Eclipse/configuration/org.eclipse.core.runtime/.keyring");&lt;br /&gt;String path = file.getAbsolutePath();&lt;br /&gt;AuthorizationDatabase aut = new AuthorizationDatabase(path, "");&lt;br /&gt;Field f = aut.getClass().getDeclaredField("authorizationInfo");&lt;br /&gt;f.setAccessible(true);&lt;br /&gt;f.get(aut);&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-2624366279957932890?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/2624366279957932890/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2009/07/eclipse-password-recovery-cvs.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/2624366279957932890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/2624366279957932890'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2009/07/eclipse-password-recovery-cvs.html' title='Eclipse password recovery (cvs, subversion, ..)'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-7310557082247219977</id><published>2009-06-30T15:14:00.000-07:00</published><updated>2009-07-13T07:57:51.551-07:00</updated><title type='text'>Waf on jython 2.5 - conclusion</title><content type='html'>Executing Waf on Jython is possible, but &lt;a href="http://waf-devel.blogspot.com/2009/06/waf-on-jython-25.html"&gt;complicated and slow&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;After discarding many possible causes (threading, garbage collection), &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;the&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;problem&lt;/span&gt; has &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;finally&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;been&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;located&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;in&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;the&lt;/span&gt; &lt;a href="http://bugs.jython.org/issue1389"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;Jython&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;subprocess&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;execution&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;Since&lt;/span&gt; &lt;a href="http://en.wikipedia.org/wiki/Fork_%28operating_system%29"&gt;os.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;fork&lt;/span&gt;&lt;/a&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;might&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;allocate&lt;/span&gt; too &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;much&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;memory&lt;/span&gt;, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;Jython&lt;/span&gt; uses &lt;a href="http://en.wikipedia.org/wiki/Fork_%28operating_system%29"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;ProcessBuilder&lt;/span&gt;&lt;/a&gt; for executing external programs (new in Java 1.5).&lt;br /&gt;&lt;br /&gt;Update: Java itself does not seem to be slow at launching processes:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;~/tmp/pb &gt; javac Fu.java&lt;br /&gt;~/tmp/pb &gt; time java Fu&lt;br /&gt;1.63user 3.87system 0:05.89elapsed 93%CPU (0avgtext+0avgdata 0maxresident)k&lt;br /&gt;0inputs+64outputs (1major+567624minor)pagefaults 0swaps&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The code of Fu.java is the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import java.io.*;&lt;br /&gt;import java.util.*;&lt;br /&gt;public class Fu {&lt;br /&gt;    public static void main(String args[]) throws IOException {&lt;br /&gt;        for (int i = 0; i &lt; 1000; ++i) {&lt;br /&gt;            ProcessBuilder p = new ProcessBuilder("ls", "-l", "/tmp");&lt;br /&gt;            p.start();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-7310557082247219977?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/7310557082247219977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2009/06/waf-on-jython-25-conclusion.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/7310557082247219977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/7310557082247219977'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2009/06/waf-on-jython-25-conclusion.html' title='Waf on jython 2.5 - conclusion'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4016193628170998370.post-9101866411520835716</id><published>2009-06-19T13:46:00.000-07:00</published><updated>2009-06-19T15:22:53.590-07:00</updated><title type='text'>Waf on Jython 2.5</title><content type='html'>&lt;a href="http://www.jython.org/"&gt;Jython 2.5&lt;/a&gt; has been released a few days ago, and since Waf somehow &lt;a href="http://code.google.com/p/waf/issues/detail?id=434"&gt;supports it&lt;/a&gt;, I wanted to have a closer look. Jython is an implementation of the &lt;a href="http://python.org/"&gt;Python programming language&lt;/a&gt; for the Java virtual machine.&lt;br /&gt;&lt;br /&gt;The supposed benefits of Jython are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A &lt;a href="http://www.grouplens.org/node/244"&gt;different&lt;/a&gt; threading model able to use multicore processors&lt;/li&gt;&lt;li&gt;The use of the &lt;a href="http://java.sun.com/javase/technologies/hotspot/"&gt;heavily optimized&lt;/a&gt; Java virtual machine&lt;/li&gt;&lt;li&gt;Using waf for web applications (Maven) where people usually do not have cPython&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Unfortunately, Jython seems to also use the java primitives for parsing the scripts, and executing the waf script &lt;a href="http://bugs.jython.org/issue1384"&gt;will not work&lt;/a&gt;. The main Waf script contains a compressed data island in a comment section to ease redistribution. When cPython rightfully skips the comments (except \r characters), Jython has to validate all unicode characters.&lt;br /&gt;&lt;br /&gt;For now the solution to execute waf on Jython is to use the waf directory and the waf-light script:&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;~/jython/bin/jython waf-light&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A quick benchmark can be created by using the script genbench.py located in the &lt;a href="http://code.google.com/p/waf/source/browse/trunk/utils/genbench.py"&gt;waf distribution:&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;utils/genbench.py /tmp/build 50 100 15 5&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When executed, the benchmark will compile 5000 c++ files and link them by calling operating systems processes. The test was executed on a laptop having more than enough RAM and a dual core processor.&lt;br /&gt;&lt;br /&gt;The cPython command was:&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;waf distclean configure build clean build clean build -p -j5&lt;/span&gt;&lt;br /&gt;The average time of execution was &lt;span style="font-weight: bold;"&gt;2m15&lt;/span&gt; (std dev: 5 secs)&lt;br /&gt;&lt;br /&gt;The Jython command was:&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;~/jython/bin/jython waf-light&lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt; distclean configure build clean build clean build -p -j5&lt;/span&gt;&lt;br /&gt;The average time of execution was &lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;5m15&lt;/span&gt; (std dev: 10 secs)&lt;br /&gt;&lt;br /&gt;From a developer perspective, the java virtual machine and the jython start-up (7 seconds) slows down the edit-compile-run cyle, which is quite un pleasant (on cpython, waf starts instantly).&lt;br /&gt;&lt;br /&gt;I will have a look at the profiles to understand the source of such a difference between cPython and Jython. For now Jython is not an interesting option for Waf users, and it probably will not make other applications &lt;a href="http://blog.ianbicking.org/gil-of-doom.html"&gt;such as Scons faster any time soon either&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4016193628170998370-9101866411520835716?l=waf-devel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://waf-devel.blogspot.com/feeds/9101866411520835716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://waf-devel.blogspot.com/2009/06/waf-on-jython-25.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/9101866411520835716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4016193628170998370/posts/default/9101866411520835716'/><link rel='alternate' type='text/html' href='http://waf-devel.blogspot.com/2009/06/waf-on-jython-25.html' title='Waf on Jython 2.5'/><author><name>Waf</name><uri>http://www.blogger.com/profile/07782635933746115506</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
