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. |
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.
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 ;)
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
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.
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.
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 |
|
Powered by FogBugz


