Treat warnings as errors in a (Gnu) Makefile

I got hit again last night by a bug in my Makefile that meant I effectively ran rm -rf /*, which was not fun.

Today I have been looking for how to make Make stop if a variable is undefined.

Here’s my solution. This Makefile contains a bug (“SRCS” instead of “SRC”):

# Turn on the warning we want
MAKEFLAGS += --warn-undefined-variables

# Make sure MAKECMDGOALS is defined, so it doesn't cause an error itself
ifndef MAKECMDGOALS
MAKECMDGOALS = all
endif

SRC=hello.c

all: compile

# Fails if the Makefile contains any warnings.
# Run this Makefile with the same goals, but with the -n flag.
# Grep for warnings, and fail if any are found.
no-make-warnings:
    ! make -n $(MAKECMDGOALS) 2>&1 >/dev/null | grep warning

# Targets you want to check must depend on no-make-warnings
compile: no-make-warnings
    gcc -o hello $(SRCS)

When I run it I get:

$ make
! make -n all 2>&1 >/dev/null | grep warning
Makefile:17: warning: undefined variable `SRCS'
make: *** [no-make-warnings] Error 1

When I correct the bug I get:

$ make
! make -n all 2>&1 >/dev/null | grep warning
gcc -o hello hello.c

As expected.

To make a target warnings-resistant, you have to make it depend on the target no-make-warnings. If anyone has suggestions for how to avoid needing this, please comment.

I also posted this as a StackOverflow answer: How to treat a warning as an error in a Makefile?.

Encapsulation as passing on responsibility

I recently dealt with some code that I felt was not properly encapsulated, but in a sense that I’ve not seen articulated in this way before. Please enlighten me if I missed it.

Here’s a snippet:

OutputThing manipulate( InputThing input )
{
    ProcessingThing proc( input );
    moreProcessing( proc.intermediateResult, input );
    return OutputThing( proc );
}

This function takes in some input and returns some output, using a ProcessingThing to do some work.

I needed to make a change to ProcessingThing to support some functionality, and I fell foul of something I didn’t expect.

I wanted to transform my input a bit, and wrote that code inside ProcessingThing. What I didn’t expect was that the untransformed input would later be used (in the moreProcessing call). The moreProcessing code failed because the transformation I had done made the ProcessingThing inconsistent with the InputThing.

Obviously, I should have checked more carefully.

But, it struck me that there is a pattern here. We are processing something by passing it from step to step in a “production line” of code. By re-using something from an older step, we violate this metaphor of passing on responsibility, because suddenly there are two copies of our input – it wasn’t passed on at all.

This feels a bit like we’ve violated the encapsulation of input by ProcessingThing, but maybe I’m stretching the word encapsulation too far?

I feel like if ProcessingThing properly encapsulated the details of InputThing, we wouldn’t need to re-use input later.

In fact, the fix in my case was to put the moreProcessing logic into ProcessingThing, meaning there was no need to refer back to the original input. I think this supports the argument that we are talking about encapsulation.

What is a good company?

I’ve been trying to work out what I think would be a good company to work for. Here’s what I’ve got so far. Please comment pointing out what I got wrong and missed out.

Be coo

We believe a company should be a good place to work.

We sum that up in one rule:

“be coo”

Rules

We define being coo like this:

  • Value humans
  • Be small, and do not persue growth as a goal
  • Be privately owned
  • Make something that people want
  • Get paid for what you do
  • Contribute to wider society

More detail:

Value humans

Be kind to people: all people, including your customers, your employees and your boss.

Use in-person communication whenever possible, and otherwise use live video chat. For talking about careers, performance etc. never settle for voice-only or text.

Regularly meet the people you manage and encourage them about what they are doing well. Rarely, talk to them about what didn’t go well. Sometimes, if someone is not able to do a role it is better for everyone if their role changes or they get another job. When it looks like this might be the situation, communicate clearly and honestly about it with them both before that decision is made and afterwards.

In performance reviews, gently reprimand people who regularly work more than their contracted hours.

Have a policy on acceptable behaviour, which is enforced by humans telling other humans what they did was not OK, when it wasn’t.

Do your best to employ people based on their ability to do the job. This includes not employing them because:

  • They look or sound right
  • They have spare time (e.g. don’t exclude someone because they don’t do any open source)
  • They seem like they are “one of us” or “get it”

Instead, look for evidence that they can do the job (this might include open source contributions, obviously), and that you can work with them. Being able to do the job will mean that they “get” things, and being able to work with them will mean that you can communicate effectively with them.

This is obviously hard. There are contradictions in the sentences above. Pro-actively invite feedback, accept negative feedback, and work to improve.

Be small, and do not persue growth as a goal

Growth is a stupid goal. Aim to do a good job. Aim to make enough money to pay your employees (and/or yourself) well. Aim to be the right size to do a good job for your customers.

Be privately owned

If you are owned by shareholders, you have a duty to prioritise shareholder value. This is in conflict with some of the rules, so don’t do it.

Make something that people want

You have to make something that people will buy or pay for, otherwise you won’t last long.

But, ask yourself whether people are glad that your company exists?

Make what you do something worthwhile: something that benefits people.

Get paid for what you do

If you don’t spend all day selling advertising, don’t get paid for selling advertising.

Find customers who want to pay you for the work you do. If your customers are actually benefitting from a concealed side-effect of what you do, the temptation to lie to them or fool them will be strong. (In reality, they are not your customers, and you won’t value them.)

Contribute to wider society

Give people time off to do voluntary work. Within reason, don’t tell them what that can or can’t be.

Contribute bug reports, documentation and code to open source projects you use for your work.

Donate some of your profits to good causes supported by the staff.