Your Build Script Method
If you want to keep to the "bash build method", then you are probably best off "touching" a file (touch lastbuild
) when the build script is ran and completes the build. In addition the build script could then look for the file generated by touch (if it doesn't exist, assume a build is needed), or if it exists use find
to see if any newer files exist:
find . -name "*.[ch]" -newer lastbuild
and then build if that output is 1 or more lines (could be checked with something like wc -l
).
Using Make instead
This is best managed by something like a Makefile (specifically used to do this kind of dependency checking).
default: all all: dependency1.o dependency2.o dependency1.o: dependency1.c ./make_common_lib.bsh build dependency2.o: dependency2.c ./make_common_lib.bsh build install: ./make_common_lib.bsh install
Creating a dummy "build" script:
$ cat make_common_lib.bsh #! /bin/sh echo "Build $1"
We can now run make:
$ make ./make_common_lib.bsh build Build build ./make_common_lib.bsh build Build build
You could also replace the ./make_common_lib.bsh build
with the command that ./make_common_lib.bsh build
would issue to build dependency1.o
etc:
dependency1.o: dependency1.c gcc -c dependency1.c
Makefiles also allow for symbol substitution, so you could declare the complier and compiler flags earlier in the Makefile:
CC=/usr/bin/gcc CFLAGS=-O2 -Wall
and then make references to them in your rules:
dependency1.o: dependency1.c $(CC) $(CFLAGS) -c dependency1.c
Note that the line that is indented after a dependency declaration must start with a tab and not spaces.
Shortening dependency rules list
The OP asked if it's possible to do shorter ways of declaring all dependencies. It is possible with a few tricks using GNU's make (note not all these will work with vanilla make).
You can do variable substitution. Given the declaration:
SRCS=dependency1.c dependency2.c dependency3.c
You can then create an objects rule using variable substitution:
OBJS=$(SRCS:.c=.o)
this will replace all .c
's with .o
's. In effect giving a line of the form:
OBJS=dependency1.o dependency2.o dependency3.o
You can then further do a shortening of the "compile command" using the special variables $<
and $@
:
.c.o: $(CC) $(CFLAGS) -c $< -o $@
$<
represents the prerequisite in GNU make parlance (or dependency as I've called it) and $@
the target, and so it will end up issuing:
/usr/bin/gcc -Wall -O2 -c dependency1.c -o dependency1.o /usr/bin/gcc -Wall -O2 -c dependency2.c -o dependency2.o . . .
Putting this all together, with linking options and a command to link and compile the executable $(TARGET)
:
# Globals CC=/usr/bin/gcc CFLAGS=-Wall -O2 LDFLAGS=-L/usr/local/lib LIBS=-ldependencylib # declare all the sources SRCS=dependency1.c dependency2.c # declare the objects files using variable substitution (find .c and replace with .o) OBJS=$(SRCS:.c=.o) # Target executable name: TARGET=myexefile default: all all: $(TARGET) @echo Target has been built $(TARGET): $(OBJS) $(CC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LIBS) .c.o: $(CC) $(CFLAGS) -c $< -o $@ install: ./make_common_lib.bsh install
Note that there are many things you can do with GNU make, and it is well documented here GNU Make Manual.
make
? It is explicitly designed to handle this requirement.make depend
ormake dep
to regenerate the list).