Session 4
Ingmar Steiner
2017-05-24
Developing and building software is an iterative process.
Eventually, the software is ready to use (according to some specification), and can be “shipped”, i.e., released.
Inevitably, more development work needs to be done, due to:
A new version is developed and released.
Open-source software (OSS) models can blur the boundaries between these perspectives.
Specialized build tools can help developers automate this build/test/release lifecycle
They should produce reproducible builds given the same source code
SCM hooks can further automate the lifecycle (for continuous integration testing)
Remember:
These are just tasks.
We might as well just
A build script describes the tasks which must be performed to build a project.
A “build script” could just be a README
file:
The user would need to manually follow the instructions.
A “build script” could also be an actual shell script:
build.sh
#!/bin/sh
do_this() { echo "doing this"; }
do_that() { echo "doing that"; }
do_something_else() { echo "doing something else"; }
# main
do_this
do_that
do_something_else
“Real” build scripts can be parsed by build tools for automatic build execution.
This requires a specific format/syntax (depending on the tool)
Makefile
do_this:
@echo 'doing this'
do_that:
@echo 'doing that'
do_something_else:
@echo 'doing something else'
GNU Make build scripts (Makefile
s) define a number of rules (i.e., build tasks).
target: prerequisite
recipe
make target
will run recipe
prerequisite
is defined, make prerequisite
will be run firstrecipe
must be an actual tab!
make
is run with no explicit rule argument, the first one is invoked.Makefile
do_something_else: do_that
@echo 'doing something else'
do_that: do_this
@echo 'doing that'
do_this:
@echo 'doing this'
Rules are normally used to create file targets.
somethingelse: that
touch somethingelse
that: this
touch that
this:
touch this
clean:
@rm -f this that somethingelse
File modification timestamps are used to determine which rules are up-to-date.
build.xml
<project default="something else">
<target name="this">
<echo message="doing this"/>
</target>
<target name="that" depends="this">
<echo message="doing that"/>
</target>
<target name="something else" depends="that">
<echo message="doing something else"/>
</target>
</project>
Rakefile
task :this do
puts "doing this"
end
task :that => :this do
puts "doing that"
end
task :something_else => :that do
puts "doing something else"
end
task :default => :something_else
build.gradle
defaultTasks "something_else"
task 'this' << {
println "doing this"
}
task that(dependsOn: 'this') << {
println "doing that"
}
task something_else(dependsOn: 'that') << {
println "doing something else"
}
build.py
from pybuilder.core import task, depends
@task
def this():
print "doing this"
@task
@depends("this")
def that():
print "doing that"
@task
@depends("that")
def something_else():
print "doing something else"
default_task = "something_else"
Typical workflow:
But these are also just tasks!
Mixing external tools and custom scripts is common
Adding tests is a good idea!
Tasks include:
Makefile
plot.svg: data_words.txt
@gnuplot -e '\
set terminal svg;\
set output "plot.svg";\
set size ratio 0.5;\
set boxwidth 0.5;\
set style fill solid;\
plot "data_words.txt" using 1:xtic(2) with boxes'
data_words.txt: data_lower.txt
@perl -ne '\
@w = split /[^a-z]+/;\
foreach (@w) {\
$$w{$$_}++;\
}\
END {\
foreach (keys(%w)) {\
printf "%d\t%s\n", $$w{$$_}, $$_\
}\
}' < data_lower.txt | sort -nr | head -n 20 > data_words.txt
data_lower.txt: data_stripped.txt
@tr '[:upper:]' '[:lower:]' < data_stripped.txt > data_lower.txt
data_stripped.txt: data.txt
@perl -pe 's/_(.+?)_/$1/g' < data.txt > data_stripped.txt
data.txt:
@wget 'http://aleph.gutenberg.org/1/7/9/5/17958/17958-8.zip' -O - | funzip | recode latin1..utf8 > data.txt
README
Note: Alternate location!