Stuff That Works part 2: One Command Build
Last week I wrote how important it is you can set up your build environment by running just one command.
Well, perhaps it is a worthy target to aim for, even if you miss it slightly. I showed you our build environment set up:
$ wget -O- http://server/1cmdenv.sh | sh
$ cd universe
$ make client-server-5.5x
Strictly speaking, that’s 3 commands (wget, cd, make). I’ll argue that cd is not really a “command”, as such, and since we have so many source trees you need 2 commands: 1 to check out the “tree-of-trees” or “universe” as we call it, and 1 to check out the source tree you want to build. I would say that is as close to one command build environment setup as we can get.
The other alternative would be to create separate setup commands for each source tree. Then where do you store these commands? Probably in the version control. But then you need another command to check them out. So, 2 commands is reasonably close to the ultimate goal.
Now to the subject of this post: The one command build.
We have chosen the one command to be: make. Running just “make” with no parameters performs a full build. With full build I mean it produces the installation package that is shipped on cdroms and uploaded to web sites.
Whatever the command is, it is important it does everything with no manual tweaking.
If there are manual steps in your build procedure, someone, somewhere, sometime when you least expect it, will get them wrong. Script it. All the way.
Even when your build is just one command, someone will think he is in a hurry and he doesn’t have time to run the one command. He will try to cut corners. He will think: “I already have module 1 built on my workstation. I’ll use that and build modules 2 and 3 by hand and execute the packaging command from the temp directory. I’ll save 10 minutes.” Beware! That is the way dragons lie.
What’s wrong with some shortcuts? Nothing if you can be absolutely sure you know what you are doing. Can you? Do you trust yourself? You do remember what causes most accidents in nuclear power plants? Human error.
4 months ago one man at the waterworks of Nokia, Finland (the city, not the phone maker) accidentally left one valve open and as a result contaminated the drinking water of tens of thousands of people. It took months to clean up the water pipes.
Long, long time ago I attended a lecture on fault tolerant systems. The lecturer said: “If you only remember one thing about this lecture, let it be this: The easiest way to build a fault tolerant system is to place the system in a very strong cabinet, lock the door and lose the key.”
In other words, eliminate the human factor.
When we run “make” in our source tree, it will do at least these things:
- generate dependencies
- export header files and string tables from a MIB file (contains all the settings and alerts of a software product in the F-Secure Policy Manager system)
- run a Perl script to generate code from the headers exported in previous step
- run another Perl script to verify string tables above match the localized string tables
- compile and install the unit test framework
- compile and run unit tests
- run a few static analyzers
- compile everything that is needed
- create RPM and DEB packages from the compiled code
- create a self-extracting installer from the RPM packages and an APT repository from the DEB packages
- export system tests from the source tree to be executed on the build by an automatic test system
- copy all the stuff that was generated to a separate file server
I’m sure I forgot a few steps in the above list. There’s too many to remember. The beauty of it is: I don’t have to. The one build command does it all for me.
When the build is just one command, it is easy to automate it. When the build just happens automatically, it further removes any possibility to screw it up. Create a cron job to make the build every night.
When you have a cron job making the build every night, why not make it every hour? Or every 15 minutes? When you have that, why would you bother making a build by hand ever again if a cron job is going to do it anyway in a few minutes. And it will do it better than you. Always the same way.
That sounds like Continuous Integration. Maybe I’ll write about that next week.