File: cbuild

package info (click to toggle)
xplot 1.19-9.2
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 460 kB
  • sloc: ansic: 1,264; sh: 359; makefile: 86
file content (368 lines) | stat: -rwxr-xr-x 10,213 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
#!/bin/sh

############### configurable settings, can be overruled in cbuild.def
CC=g++
CFLAGS="-c -Wall -O2 -g"
LFLAGS="-O2"
LIBNAME=cbuild
ARFLAGS=rv
RANLIB=ranlib
OTHERLIBDIRS=""
OTHERLIBS=""
DESTPROG=""
INSTALL=""
EDITOR='xrun jove +$LINE $FILE'

############### print error msg and die
error ()
{
    echo "$PROG": $*
    exit 1
}

############### print a message string
message ()
{
    echo "$PROG": $*
}

############### now source cbuild.def if it exists
if [ -f "cbuild.def" ] ; then
    . ./cbuild.def || error syntax error in cbuild.def
fi    

############### non-configurable settings
VER=0.05
PROG=`basename $0`
STARTDIR=`echo $PWD`
FULLLIB="$STARTDIR/lib$LIBNAME.a"
CHANGES=no

############### run: run a command or exit upon failure
run ()
{
    tmpfile=/tmp/cbuild.$$.out

    message "$*"
    $* > $tmpfile 2>&1
    
    result=$?
    cat $tmpfile
    
    if [ $result -ne 0 ] ; then
	message program $1 reports error
	# see if we can parse the output and invoke the editor
	if [ "$1" = "g++" -o "$1" = "gcc" ] ; then
	    if [ "$EDITOR" != "" ] ; then
		errmsg=`egrep '^[a-zA-Z]+\.[a-zA-Z]+:[0-9]+' $tmpfile | \
			head -1`
		FILE=`echo $errmsg | awk -F: '{print $1}'`
		LINE=`echo $errmsg | awk -F: '{print $2}'`
		message starting editor
		eval "$EDITOR"
		rm $tmpfile
	    fi
	fi
	error aborted.
    fi
    rm $tmpfile
	
}    

############### compiledir: compile all in current dir,
# place objects in STARTDIR, given prefix $1 to be used for object files
compiledir ()
{
    ccfiles=`ls -1 *.cc *.c 2>/dev/null`
    hfile=`ls -1 *.h 2>/dev/null`
    
    if [ -z "$hfile" -o ! -f "$hfile" ] ; then
	message warning: no header file found in this directory
    else
	touched=no
	for ccfile in $ccfiles ; do
	    if [ $hfile -nt $ccfile -a $touched = no ] ; then
		message header "$hfile" is newest, touching all sourcefiles
		run touch "$ccfiles"
		touched=yes
	    fi
	done
    fi
    
    for ccfile in $ccfiles ; do
	ofile="$STARTDIR/$1$ccfile"
	ofile=`echo $ofile | sed 's/\.c/.o/g' | sed 's/\.oc/.o/g'`
	compileit=no

	if [ -f $ofile ] ; then
	    if [ $ccfile -nt $ofile ] ; then
		compileit=yes
	    fi
	else
	    if [ ! -f "$FULLLIB" -o $ccfile -nt "$FULLLIB" ] ; then
		compileit=yes
	    fi
	fi

	if [ $compileit = yes ] ; then
	    run "$CC" "$CFLAGS" $ccfile -o $ofile
	    CHANGES=yes
	fi
    done
}    

############### build all classes in subdirs
buildclasses ()
{
    dirs=`cat cbuild.classes`
    if [ "$dirs" = "" ] ; then
	message no subclasses to compile
    else
	message will build subclasses: $dirs
	prefix=1
	for d in $dirs ; do
	    message building subclass: $d
	    cd $d || error cannot changedir to $d
	    compiledir $prefix
	    cd "$STARTDIR"
	    prefix=`expr $prefix + 1`
	done
    fi
}

############### make test programs in subdirs/test, one testprog per file
maketest ()
{
    dirs=`cat cbuild.classes`
    message checking for test progs
    for d in $dirs ; do
	if [ -d $d/test ] ; then
	    cd $d/test || error cannot changedir to $d/test
	    ccfiles=`ls *.cc 2>/dev/null`
	    for ccfile in $ccfiles ; do
		out=`echo $ccfile | sed 's/\.cc//g'`
		if [ ! -f $out -o $ccfile -nt $out -o "$CHANGES" = "yes" ]
		then
		    message making test program $d/test/$ccfile
		    if [ "$OTHERLIBDIRS" = "" ] ; then
			Lflag="-L$STARTDIR"
		    else
			Lflag="-L$STARTDIR $OTHERLIBDIRS"
 		    fi
		    if [ "$OTHERLIBS" = "" ] ; then
			lflag="-l$LIBNAME"
		    else
			lflag="-l$LIBNAME $OTHERLIBS"
		    fi
		    run "$CC $LFLAGS -o $out $ccfile $Lflag $lflag"
		fi
	    done
	    cd $STARTDIR
	fi
    done
}    

############### makelib: combine objects into one FULLLIB
makelib ()
{
    objects=`ls *.o 2>/dev/null`
    if [ ! -z "$objects" ] ; then
	run "ar $ARFLAGS $FULLLIB $objects"
	if [ ! -z "$RANLIB" ] ; then
	    run ranlib "$FULLLIB"
	fi
	run "rm $objects"
	CHANGES=yes
    fi
}

############### makedestprog: make the final program from the lib
makedestprog ()
{
    message "making destination program $DESTPROG"

    if [ "$OTHERLIBDIRS" = "" ] ; then
	Lflag="-L$STARTDIR"
    else
	Lflag="-L$STARTDIR $OTHERLIBDIRS"
    fi
    
    if [ "$OTHERLIBS" = "" ] ; then
	lflag="-l$LIBNAME"
    else
	lflag="-l$LIBNAME $OTHERLIBS"
    fi

    if [ ! -f "$DESTPROG" -o "$FULLLIB" -nt "$DESTPROG" ] ; then
	run "$CC $LFLAGS -o $DESTPROG $Lflag $lflag"
    else
	message "destination program $DESTPROG is up to date"
    fi
}

############### makeinstall: run the final installation
makeinstall ()
{
    if [ "$INSTALL" != "" ] ; then
	run "$INSTALL"
    fi
    if [ "$INSTALL1" != "" ] ; then
	run "$INSTALL1"
    fi
    if [ "$INSTALL2" != "" ] ; then
	run "$INSTALL2"
    fi
    if [ "$INSTALL3" != "" ] ; then
	run "$INSTALL3"
    fi
}   

############### show divers help
helpme ()
{
    if [ "$1" = "help" ] ; then
	cat << ENDHELP
The cbuild script is a generic compiler driver, though directed towards C++
programs with class sources in subdirectories. Try:
    "cbuild whatfor" for general info
    "cbuild files" for resource files descriptions
    "cbuild def" for an  overview of settings in resource cbuild.def
    "cbuild mangling" for the internally used name mangling
    "cbuild author" for my name/address.
ENDHELP

    elif [ "$1" = "author" ] ; then
	cat << ENDHELP
cbuild by Karel Kubat (karel@icce.rug.nl). Please mail me suggestions or bug
reports, I'll do what I can to fix or incorporate features (if I find the
time..).
ENDHELP

    elif [ "$1" = "whatfor" ] ; then
	cat << ENDHELP
The cbuild script is meant to compile your C++ programs, given the following
setup:
    some directory with sources, say
	~/cc
    subdirectories with classes, say
	~/cc/oneclass and
	~/cc/otherclass
cbuild will compile all .cc files in the current directory and in underlying
class subdirectories and place the resulting objects in one library. The
program can then be constructed from that library. The big advantage over make
is that you don't have to specify all source files, cbuild does that for
you. The big disadvantage is that cbuild has only little dependency checking.
cbuild relies on resource (definition) files, try "cbuild files" for info.
Oh, and cbuild will work for .c files too.
ENDHELP

    elif [ "$1" = "files" ] ; then
	cat << ENDHELP
The first relevant file is "cbuild.classes". You must list the
subdirectories which contain class sources here. E.g., given two subdirs
"oneclass" and "otherclass", each containing sources, your resource file
"cbuild.classes" would look as:
oneclass
otherclass
You never have to specify the current directory in cbuild.classes, that's
implicit. If you don't have subdirectories, don't create cbuild.classes or
leave that file empty.
This file is used in cbuild's name mangling, try "cbuild mangling" for
info. Another optional though useful resource file is "cbuild.def", which
defines some variables. Try "cbuild def" for info.
ENDHELP

    elif [ "$1" = "mangling" ] ; then
	cat << ENDHELP
cbuild will mangle object file names before these objects are placed into
the library. The purpose is that more class subdirectories may contain the
same filenames, e.g. oneclass/init.cc can coexist with otherclass/init.cc.
The trick is that these files lead to 1init.o and 2init.o, which will occur
separately in the library. You don't need to worry about name mangling, just
be glad that it's there.
cbuild constructs the prefix for all objects (1, 2, etc.) using the line
count in the definition file "cbuild.classes". Say you have three subdirs
    oneclass
    anotherclass
    thirdclass
specified in this order in cbuild.classes. A source file init.cc from
thirdclass is then mangled into the object file 3init.o.
ENDHELP

    elif [ "$1" = "def" ] ; then
	cat << ENDHELP
The resource file cbuild.def may contain variables, all in the form
    VARIABLE=value
Used variables are:
    CC: your favorite C++ compiler, default is "g++".
    CFLAGS: compilation flags, default is "$CFLAGS". Useful setting is e.g.
	"-c -g" to include debugging code.
    LFLAGS: linker flags, default is "$LFLAGS". Useful setting is again "-g".
    LIBNAME: the name of the destination library, default is "$LIBNAME" which
	gives you "lib$LIBNAME.a". E.g., if you're constructing a program
	"rm", you might want "librm.a" -- so you'd set this to "rm".
    ARFLAGS: flags to pass to ar, default is "$ARFLAGS".
    RANLIB: your ranlib program, set to "" if you don't have / need one.
    OTHERLIBS: other libraries besides LIBNAME you might need. A useful setting
	is e.g. "-lbsd". Note: include the "-l" flag in this name. Default
	is empty.
    OTHERLIBDIRS: other library-containing directories than the current dir,
	e.g. /home/user/divers/libsuper.a would be linked to the program with
	    OTHERLIBS="-lsuper"
	    OTHERLIBDIRS="-L/home/user/divers"
    DESTPROG: the final program to build using the constructed library and
	possibly other libs. Default: nothing, which only constructs the
	library. E.g.:
	    DESTPROG=/usr/bin/myprog
    INSTALL: possible last installation actions, default is nothing. E.g.:
	    INSTALL="cp myprog.1 /usr/man/man1". Similarly, you have three
	    more: INSTALL1, INSTALL2, INSTALL3.
    EDITOR: Given the compiler "g++" or "gcc", cbuild will try to invoke your
	favorite editor when compilation fails. Set EDITOR to an empty string
	if you don't want this behavior, or state your editur using $FILE for
	the filename and $LINE for the line number. Default is:
	    EDITOR='xrun bjove +\$LINE \$FILE'	# my default
ENDHELP

    else
	error no such help subject, try cbuild help
    fi
    exit 1
}

############### main prog
# banner
message Version "$VER"

if [ "$1" != "" ] ; then
    helpme $*
fi    

# check for class subdirs definition
if [ ! -f "cbuild.classes" ] ; then
    message "cbuild.classes not found, assuming no subdirs"
else
    # build classes in subdirs
    buildclasses
fi    

# build classes in startdir
message compiling in "$STARTDIR"
compiledir

# combine objects into one lib, make test progs
if [ "$CHANGES" = "yes" ] ; then
    makelib
fi

if [ -f "cbuild.classes" ] ; then
    maketest
fi     

if [ "$DESTPROG" != "" ] ; then
    makedestprog
else
    message "No DESTPROG setting in cbuild.def, not making program."
fi    

makeinstall