Sunday, April 27, 2008

Exit, Pursued by a Bear

"Exit, pursued by a bear." That's how Antigonus dies in The Winter's Tale. It's the most infamous stage direction in Shakespeare, and I have a story about it.

I took a Shakespearean Comedies class as an undergraduate English major, and The Winter's Tale was one of the plays we read. To kick off the discussion, the prof asked one of the students what she thought of it.

"It was too long!" she said. Think of a Valley Girl with a Southern accent. She kinda giggled when she said it.

"Well, that's a very insightful comment," the prof said with just the right touch of sarcasm. (I myself tend to pour sarcasm on my words like A-1 on a burnt steak; this was more of a light flavoring, just enough to let you know it was there. Magnifique!)

Then he went around the room and had every single student say something about the play. There were -- oh, I dunno, maybe 80 of us. Some of the comments were more insightful than others, but you can be damn sure nobody else said "it was too long." Hick/Valley Girl just sank deeper and deeper into her chair with each non-inane comment.

I was sitting in the back row, so by the time he got to me, most of what I wanted to say had been said. But I scrounged up something to say about that odd stage direction -- something to the effect that I didn't think a modern audience would buy it, but maybe it told us something about how Shakespeare's audiences differed from us in their expectations, in what they accepted as stage reality. (Or, I'd add now, maybe they just didn't care -- maybe they sorta accepted it as a bit of spectacle.) Hick/Valley Girl sank another notch and the prof moved on.

Nobody ever made another comment like that in that class.

Friday, April 25, 2008

GNUmake a Grown Man Cry

A co-worker asked me to help solve a thorny GNUmake problem the other day. When he did a make clean, GNUmake would apparently first do a make depend, and then do the make clean.

This might be simply a minor annoyance in many systems, but in this case, the unwanted make depend wasted a lot of time, because he has a lot of generated code and his depend target naturally depends on that. So GNUmake first built his code generator, then ran the code generator, then invoked g++ to scan all of the source to generate the depends file. Only then would the make clean run -- and, of course, to add insult to injury, that wiped out all of the auto-generated code (and the executable code generator, though not its source, natch). It also wiped out the depends file.

Seemed like kind of a waste. But what really bugged him -- and me -- was just the fact that we didn't understand it. In particular, the clean target had no dependencies, so why was GNUmake choosing this other random target to make first?

GNUmake's debugging output wasn't immediately informative, but after poking at the problem for a while, we narrowed it down to a side effect of the GNUmake include directive. His main makefile naturally included the depends file, and in GNUmake, for some reason -- I'm sure this must make sense to someone, but not to me -- the include directive first includes the named makefiles, and then automatically adds them to the list of targets to be remade. The other two flavors of include -- sinclude and -include -- also do that.

That explained GNUmake's behavior: GNUmake reads the main makefile, includes the depends file (since it's a makefile too; that's the whole point), then adds the depends file to the list of targets to make. Since the depends file depends on his source code -- including the auto-generated code -- that meant invoking his code generator, and so on and on and on.

But that's only part of the problem. We know why GNUmake is doing that seemingly weird thing, but how do we stop it? Our best guess after RTFM was, you can't: there's no option to GNUmake's include that turns off this behavior. If you don't want your included makefiles remade, tough luck.

But documentation is one thing, code's another. That's why God, or rather, RMS, gave us the source code. So I spent a little while trawling through the GNUmake source and discovered a way to work around this behavior. GNUmake has a special case that turns off the makefile-remaking: if the makefile is listed as the target of more than one double-colon rule, and one of the rules has commands but no dependencies, it skips remaking that makefile for fear of getting stuck in an infinite loop.

So the fix was to add such a rule to the depends file itself, something like this:

# ... invoke code generator ....
# ... invoke g++ to scan source and create $(DEPENDSFILE) ....
# Hack starts here:
printf >>$(DEPENDSFILE) '\n$$(DEPENDSFILE) ::\n'
printf >>$(DEPENDSFILE) '\t@echo suppress remaking $$(DEPENDSFILE)\n'

# ...

include $(DEPENDSFILE)

(He also tried another workaround, involving using a separate file to effectively be the timestamp for the depends file, but he liked that even less. So the above hack lives.)

With this change, GNUmake now reads the main makefile and the depends file, sees the second double-colon rule for the depends file in the depends file itself, and skips remaking the depends file.

One good longer-term fix would be to attack the problem more directly: add an include-like directive that has the effect we want, including the target file(s) without adding them to the targets list.

Meanwhile, the short-term fix is unfortunately ugly. There's a reason, I think, why the word "hack" sounds like a cat bringing up a hairball. But it at least gets my co-worker back in business for the moment. Doing a simple make clean is no longer a reason to take a coffee break.

And the big lesson: this may be an ugly hack, but without the source code, we'd have been simply up the creek -- and that would be even uglier. Score one more for RMS.

Wednesday, April 23, 2008

So I'm Jewish, Apparently

My wife is well along in the process of converting to Judaism. I was raised Presbyterian, she was raised Catholic; I've been a devout atheist since I was about 10, and she's agnostic. But she likes the traditions of Judaism, its questioning nature, the community and history around it. So she's taking conversion classes.

About a month ago, she tells my brother about it, and he says, "Oh, yeah -- you know, we're a quarter Jewish."

We're what again?

Turns out, eight or ten years back, he went to my grandmother's funeral. My grandfather's relatives were all there, and since many of them seemed to have stereotypically New York Jewish accents and mannerisms, he asked about it.

This is the story. My grandfather was born in the Bronx to a family of Russian (by way of England) Jews. He grew up and fell in love with my grandmother, but his mother insisted he couldn't marry a shiksa. He converted to Christianity, married her anyway, and nobody bothered to mention any of this for more than 30 years. (And my brother didn't mention it to me for another decade after he found out. I asked him, "Are we anything else I should know about? Were we raised by wolves until we were ten?")

So I'm Jewish, apparently -- a quarter Jewish, at least. But in a funny way. I'm not Jewish in the right way for Jews to consider me Jewish (because my mother wasn't Jewish, because her mother wasn't), yet I'm Jewish enough for the Nazis to have killed me. Perfect.

I have zero emotional attachment to the religion and culture, since it wasn't part of my world growing up. I consider the superstitious aspect of Judaism silly, same as any other religion. Yet there are aspects of Judaism I respect and relate to -- its emphasis on trying to be a good person, on learning, on questioning, on doing good in the world, on freedom and human rights -- and I suspect that's because these were family values, though never explicitly connected to Judaism.

So I'm a little Jewish, maybe. But not very.

And I'm sorry, but I love, love, love bacon.