Saturday, May 1, 2010

Makefile Exploration

In my preparation for CS 240 this upcoming summer term, I delved into the C++ and Makefiles. For one of the class projects we will be making some basic data structures. I got a great start one them. There’s really not much to linked lists and such anyway. Not far into the project I grew tired of compiling everything by hand. Plus, one requirement of the project is to create a makefile. I had some previous experience with makefiles from CS 124. I looked up my old makefiles and had a good makefile up and going in no time.

Of course, as a good developer, I wanted to make the most out of code reuse. I wanted to create makefiles for following projects with little or no effort. A quick Google search revealed exactly what I was looking for. I found a short, simple makefile example that I could customize to my needs by changing only a couple lines.

After reading through more of the requirements for the projects, I soon discovered that the overall structure of the project was more complicated than I anticipated. All of the source files were to be in one directory, the header files in their own, the unit tests in another, and so on. My simple makefile only worked when all of the files were in the same directory. This time, not even Google could find results that worked for my particular wants.

I consulted the GNU make documentation directly. After a couple hours of thorough studying, deep thought, and many errors, I arrived at a solution. My first difficulty came with accessing the different files. I had a variables for each of the directories and a variable containing all of the source file names. The problem was combining the two so that directory didn’t have to be specified for each source file name. It turns out that make has a foreach function. That easily fixed the first problem.

Once the file access problem was resolved only one more problem stood in the way. This one stumped me for a while. My rule that compiled .cpp files to .o files didn’t seem to be working. The target name was .cpp.o: (this is shorthand for %.o: %.cpp). Even the GNU make manual didn’t supply a sufficient answer to this puzzle. The answer came while poking around stackoverflow.com. Someone else had a related question. From some sample code provided I changed my target to $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp. OBJ_DIR is a variable containing the name of the directory to where .o files are stored and SRC_DIR is where the source files are kept. What I came to realize is that although the % operator for all intents and purposes is a wildcard, it stays within the directory. Basically, my rule was telling the makefile to look for any .o and .cpp files in the root directory of my project. What I really wanted was the makefile to look in the respective directories for the files. As always, it’s the simple mistakes that trips up a program.

In addition to creating the basic targets, I created a few others for convenience. Some include clean, test, run, etc. I haven’t done anything yet with building unit tests and library files. That will come in due time as I find out more of what my professor expects.

I would post my source code, but I won’t so that my fellow students won’t be tempted to copy and use it without first learning how everything works by themselves. However, my source code is available at request.