The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Build numbers

I'm trying to implement build numbering in a C++ project I've been assigned to.  How to other people out there do it?  I'd like it to be automatic, and I also wonder if there's a way to do it such that I'm not checking in some sort of file every night when we do daily builds.  FYI we're using Visual Studio .NET and Perforce.
Jon B Send private email
Tuesday, March 08, 2005
 
 
I seem to remeber seeing VS plugins to do that kind of thing at http://www.codeproject.com.  We have our automated build tool do it for us (Visual Build).
Bacon
Tuesday, March 08, 2005
 
 
For perforce change numbers are the perfect build number. Given the change number you can reproduce any build at any time.
son of parnas
Tuesday, March 08, 2005
 
 
Son of Parnas: Depends on your build process - I recommend labeling what's on your machine before you build. There's always the odd left-over file ;)
Robert 'Groby' Blum Send private email
Tuesday, March 08, 2005
 
 
I found change numbers far superior in perforce than labels. Comming from CVS it was hard to switch to change numbers, they are a very different idea, but they work better imho. They identify the state of the depot at a given time. If you know the change number and the branch you want to build on you are set. You don't need to manage labels at all.
son of parnas
Tuesday, March 08, 2005
 
 
Yup, p4 change numbers make the perfect build number.  Easily reproduceable and understood by the rest of the team.
hoser Send private email
Tuesday, March 08, 2005
 
 
It happens that I am working on automating our build today, and facing exactly the same question.

Can anyone describe how to extract the head change number from Perforce? How about from Subversion?

Thanks.
Mark Send private email
Wednesday, March 09, 2005
 
 
Thanks for the replies.  I'd seen the Perforce change numbers and had thought about it but wasn't quite sure.  My current plan is to have a header file with the build number that is automatically generated by script which will run pre-build.  Is that how other folks have done it?  Another idea I might try is running a script which sets an environment variable that gets passed in as a preprocessor definition.
Jon B Send private email
Wednesday, March 09, 2005
 
 
It has been some time since using perforce, but its something like this:

p4 changes -m 1
men R pigs Send private email
Wednesday, March 09, 2005
 
 
Mark, in perforce the command p4 changes lists changesets.  The -m1 option will tell it to list the most recent and the -c CLIENT will tell it to use a particular client workspace, so if your build script uses a workspace called BUILDER then you could run:
p4 changes -m1 -c BUILDER
and get output like:
Change 34 of 2005/03/07 by jonb@JONBS_CLIENT 'Fixed sorting error (Bug #123)'

I'm probably going to call this from a python script, so I can use the -G option to marshal everything but I don't know how that will all come out at this point.

I think subversion has a similar command but I don't know it.
Jon B Send private email
Wednesday, March 09, 2005
 
 
When I needed an automatically incrementing build number and didn't have tools that would do it for me, I did something like this. First, create a file buildno.c:

int buildno(void) { return 0; }

Then create a shell script called upd_buildno:

#!/bin/sh

buildno=`grep return buildno.c | sed 's/[^0-9]//g'`
echo "int buildno(void) { return `expr $buildno + 1`; }"  > buildno.c

Finally, create a Makefile target for buildno.c which depends on all other source files:

buildno.c: $(SRCS)
    ./upd_buildno

(If anyone tries to actually use this, be sure to replace the spaces at the start of the last line with a tab.)
comp.lang.c refugee
Wednesday, March 09, 2005
 
 
Notes to pedants:

1. Yes, the grep is unnecessary. At least, it's unnecessary until somebody decides to re-indent buildno.c.
2. Defining the build number as a macro in a header file might be more correct, but doing so introduces a circular dependency between that file and any source files that include it.
comp.lang.c refugee
Wednesday, March 09, 2005
 
 
Refugee,

I bet there are some of us who don't know what you meant by

"2. Defining the build number as a macro in a header file might be more correct, but doing so introduces a circular dependency between that file and any source files that include it."

Would you please explain this differently? An example would be good, I think.

Thanks!

Silly Me
Silly Me
Friday, March 11, 2005
 
 
Sure, I'll explain it, with apologies to the OP for completely hijacking the thread.

The fact is that the header file method I described *doesn't* introduce a circular dependency. I wasn't thinking clearly when I wrote that. However, I do still think that putting the build # in a header file is a bad idea. Consider this trivial example. Once again, replace leading spaces with a tab.

foobar: foo.o bar.o
    $(CC) $(LDFLAGS) -o foobar foo.o bar.o
foo.o: foo.c buildno.h
bar.o : bar.c buildno.h
buildno.h: foo.c bar.c
    ./update_buildno

The key point is that each object file depends on the build number header, which in turn depends on each source file. The object files have to depend on the header so that they'll get rebuilt with the right values when it's changed. The header has to depend on every source file so that the build number will be updated whenever a file changes.

The resulting dependency graph looks like this. You'll need to paste it into something that uses a monospaced font for it to look right.

foobar --> foo.o --> foo.c
      |        +-> buildno.h --> foo.c
      |                      +-> bar.c
      |
      +-> bar.o --> bar.c
                +-> buildno.h --> foo.c
                              +-> bar.c

Simplifying a bit, we end up with this:

foobar --> foo.o --> buildno.h --> foo.c
      |                      +-> bar.c
      |
      +-> bar.o --> buildno.h --> foo.c
                              +-> bar.c

As you can see, both object files now depend on both source files. This means that when *either* foo.c or bar.c is modified, both object files will have to be rebuilt. In short, we've just lost the benefits of seperate compilation. It's not a huge deal for a small project like this, but it's devastating to large projects.

Now, let's go back to my original scheme. We have a source file which consists of either a global variable containing the build number or a function returning the build number.  We compile it seperately from the rest of the program. The other object files don't depend on it. As long as they're linked with an up-to-date build number object file, they'll get the right number. The Makefile looks like this:

foobar: foo.o bar.o buildno.o
    $(CC) $(LDFLAGS) -o foobar foo.o bar.o buildno.o
foo.o: foo.c
bar.o: bar.c
buildno.o: buildno.c
buildno.c: foo.c bar.c
    ./update_buildno

In practice, we can omit the middle three targets because make will infer them. I've left them in for clarity. Here's the dependency graph. Once again, it'll look like crap until you put it in a monospaced font.

foobar --> foo.o --> foo.c
      |
      +-> bar.o --> bar.c
      |
      +-> bar.o --> bar.c
      |                               
      +-> buildno.o --> buildno.c --> foo.c
                                  +-> bar.c

Much better, isn't it? foo.o will only be rebuilt when foo.c is changes, and bar.o will only be rebuilt when bar.c changes. That's just as it should be. buildno.o will still be rebuilt whenever any of the source files change.

Dependency handling in Makefiles is something that most people get wrong. If your interest in this goes beyond mere curiosity, I suggest reading http://www.pcug.org.au/~millerp/rmch/recu-make-cons-harm.html .
comp.lang.c refugee
Saturday, March 12, 2005
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz