--- title: Stable order for inputs layout: docs permalink: /docs/stable-inputs/ --- If building your software requires processing several inputs at once, make sure the order is stable across builds. A typical example is creating an archive from the content of a directory. Most filesystems do not guarantee that listing files in a directory will always result in the same order. Example Makefile ---------------- The following `Makefile` will result in unreproducible builds[^sorted-wildcard]:
{% highlight makefile %} SRCS = $(wildcard *.c) tool: $(SRCS:.c=.o) $(CC) -o $@ $^ {% endhighlight %}
Solutions: a) List all inputs explicitly and ensure they will be processed in that order.
{% highlight makefile %} SRCS = util.c helper.c main.c tool: $(SRCS:.c=.o) $(CC) -o $@ $^ {% endhighlight %}
b) Sort inputs:
{% highlight makefile %} SRCS = $(sort $(wildcard *.c)) tool: $(SRCS:.c=.o) $(CC) -o $@ $^ {% endhighlight %}
[^sorted-wildcard]: GNU Make used to sort the output of the [wildcard](https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html#Wildcard-Function) function until version 3.82. Watch out for locale-related issues ----------------------------------- When sorting inputs, one must ensure that the sorting order is not affected by the system locale settings. Some locales will not distinguish between uppercase and lowercase characters. For example, `tar` will by default use the filesystem order when descending directories:
{% highlight sh %} $ tar -cf archive.tar src {% endhighlight %}
A solution is to use `find` and `sort` but the following might still have differences when run under different locales:
{% highlight sh %} $ find src -print0 | sort -z | tar --no-recursion --null -T - -cf archive.tar {% endhighlight %}
The locale used to sort files must be specified to avoid any surprises:
{% highlight sh %} $ find src -print0 | LC_ALL=C sort -z | tar --no-recursion --null -T - -cf archive.tar {% endhighlight %}
This might not be the only change required for [Tar and other archive formats]({{ "/docs/archives/" | relative_url }}) as they usually embed more metadata problems.