DaedTech

Stories about Software

By

A Small, Functional Makefile

I don’t write C++ all that often these days, but I suppose that I spent so many years with it that it never really feels foreign to me when I come back to it. What does oftentimes feel foreign is generating a Makefile when developing in Linux. I’ve made enough of them over the years that I know what I’m doing but not so many that I can go off the cuff after six months or a year break from them.

So I’m sticking a sample Makefile here. This is somewhat for me to refer back to whenever I need to, but I’ll also explain some of the basics. In this example, I’m creating a little C++ application for calculating the odds of poker hands, given what is on the table at the moment. At the time of writing, the example, in its infancy, has only one class: Card. So the files at play here are card.h, card,cc and main.cpp. The main class references card.cpp, which, in turn, references its class definition header file, card.h.

all: oddscalc

card.o: card.cpp

	g++ -Wall -c -o card.o card.cpp

main.o: main.cpp
	g++ -Wall -c -o main.o main.cpp

oddscalc: card.o main.o

	g++ card.o main.o -o oddscalc

clean: 
	rm -f *.o oddscalc

So there’s the simple Makefile. If you take a look at this, the main purpose of the Makefile is, obviously, to compile the source, but also to automate linking so that, as projects grow, you don’t have increasingly unwieldy g++ command line statements. So we define a few Makefile rules. First, card.o is generated by compiling card.cc. Second, main.o is generated by compiling main.cpp. The executable is generated by linking the two object files, and “all” is the executable.

That’s all well and good, but I can eliminate some duplication and make this more configurable. I’ll use Makefile variables so that I don’t have to repeat things like “card,” “oddscalc,” and “g++” everywhere.

In addition, I can see the inevitable redundancy coming from our previous Makefile. As soon as I add hand.cpp/hand.h and deck.cpp/deck.h, I’m going to have to create rules for them as well. Well, I don’t want to do that, so I’m introducing a scheme that, in essence, says, “compile every .cpp file I give you into a .o file and link it in the main assembly.” This will be expressed with a “.cpp.o” rule.

#Defines
CC=g++
CFLAGS=-c -Wall
EXE=oddscalc
SOURCES=main.cpp card.cpp
OBJECTS=$(SOURCES:.cpp=.o)

#Build Rules

all: $(SOURCES) $(EXE)

.cpp.o:
	$(CC) $(CFLAGS) $< -o $@

$(EXE): $(OBJECTS)

	$(CC) $(OBJECTS) -o $(EXE)

clean: 
	rm -f *.o oddscalc

With this Makefile, if I want to add a new class, all I need to do is add the class's .cpp file to the "SOURCES" definition line and it will get compiled and linked for the application. (Well, obviously, I need to write the class as well, but we're just talking about the Makefile here.)

So that's it. There are a lot of things you can do with Makefiles. Some people create a variety of build configurations. "make tar" is a popular option as well. But I think that this Makefile is relatively simple and elegant, and it's easy to add to.

By

DXCore Plugin Part 3

In a previous post, I mentioned my ongoing progress with a DX Core plugin. I’d been using it successfully for some time now but had to dust it off again last week. Another convention that I’m required to abide for consistency sake but don’t much care for is explicit typing of my variables.

That is, I prefer declarations like:

var myTypeWithLongName = new TypeWithALongName();

rather than:

TypeWithALongName myTypeWithLongName = new TypeWithALongName();

I personally find the second to be needlessly syntactically noisy, and I don’t really see any benefit since the implicit (var) typing preserves strong typing and even causes the resulting type to show up in Intellisense. But, when in Rome…

Compared to my previous setup, this was relatively straightforward. Initially, I thought it would be even simpler than it turned out to be, since Code Rush itself supports the explicit/implicit conversion as an individual refactoring. I figured I’d just have to iterate through the file and call something like “Some.CodeRush.Namespace.MakeExplicit(myVariable)”.

Well, it didn’t turn out to be that easy (at least not that I found), but it did turn out to be relatively simple. Eliding the part about actually finding the variables, I was able to accomplish what I wanted with this method:

/// Convert the local variable declaration to FSG's standard of explicit typing
/// Variable object to convert
/// A string with the new type declaration
public string ConvertDeclaration(Variable variable)
{
    var myImplicit = variable as ImplicitVariable;
    string myString = variable.MemberType;
    if (myImplicit != null)
    {
        var myObjectCreation = myImplicit.Expression as ObjectCreationExpression;
        if (myObjectCreation != null && myObjectCreation.ObjectType != null)
        {
            myString = myObjectCreation.ObjectType.ToString();
        }

        var myArrayCreate = myImplicit.Expression as ArrayCreateExpression;
        if (myArrayCreate != null)
        {
            myString = myArrayCreate.BaseType.ToString();
        }
    }
    return myString;
}

This isn’t actully my finished ‘production’ code, but it’s easier to display in this format. I didn’t like the size of that method, so I created an abstract ExplicitExpressionConverter and gave it inheritors ObjectCreationExpressionConverter and ArrayCreateExpressionConverter, using a factory method creation pattern to figure out which to create, based on the variable. But while that abstraction makes the code cleaner, it makes the logic harder to document in a blog post.

So, anyway, the idea here is that you need to convert the variable you find into the appropriate type of expression. An object creation expression is standard allocation, and the array create expression is a special case. There are other special cases as well, such as null coalescing (var myFoo = someClass.GetAFoo() ?? new Foo()) and method call expression (var myFoo = someClass.GetAFoo()), but I have not yet figured out how to obtain the return type from those expressions. I’ll probably add a part 4 if/when I do.