As a software developer of 15+ years, I'm surprised at the number of other experienced developers that do not understand how software is assembled. This series of posts will describe what i see as an assembly line. My main focus will be on C and C++ based development, but all this could apply to any development environment.
This will be a multipart article. The first part will be about dealing with dependencies. The goal will be to build a reusable, predictable, sensible build system.
The most common issue I've run across is dependency management. Most places I've worked had none. You were expected to have all the libraries you needed installed, used whatever compiler was installed on the box, and hope for the best. This invariably leads to the release building machine having different compilers and libraries, which in turn leads to release bugs that no one can duplicate.
So the first step in the assembly line is to gather your dependencies, and place them into a known location. I personally prefer putting the dependencies into the same directory as my current project. This is as opposed to having a global area for dependencies. I do this for a few reasons:
- I generally work on multiple projects with slightly different dependencies. This is much easier to manage.
- Allow mobility on my local machine. I can move the project around as needed. I can copy it to another machine with a simple directory copy.
- If you have multiple versions of the project your working on, you know exactly which dependencies you are using, just by looking in your dependencies directory.
- You can build your build scripts/projects/makefile to always point to the same area. No worries about trying to find where on the system the dependencies are.
I do realize that this will mean having the same libraries on my machine, but I'm willing to pay that price.
The next decision that needs to be made is what you dependencies really are. Depending on your requirements, your dependencies could include an entire OS. You need to draw a line somewhere. For most desktop applications, you can safely assume a base set of libraries are available. I personally do not like having to install extra dependencies when I want to run some application. That may be ok, you'll have to make the decision based on your target audience. Also remember that your compiler is also a dependency.
You've now determined where and what your dependencies are. You now need the 'how'. I've used shell scripts, python scripts, Ivy, and a few other things. I even wrote my own at one point, depvault. Now matter what you choose, you need a way to describe what you dependencies are, and how to retrieve them. A few things in mind when selecting a dependency manager:
- I prefer dependency managers that use a separate, human readable file to specify the dependencies. This makes it easier to track changes in your source control, as you'll be able to see the changes in what version of a dependency you are using. Using things like externals (subversion) aren't a good solution. Not enough visibility.
- You should also be able to specify a version of that dependency, and possibly additional information. The additional information could be anything from what platform you need, to debug or release mode, to developer versions (header files and .lib/.a) or distributables (executables or shared libraries.).