---
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.