1#!/usr/bin/env bash
2
3bup_find_prog()
4{
5    # Prints prog path to stdout or nothing.
6    local name="$1" result="$2"
7    TLOGN "checking for $name"
8    if ! [ "$result" ]; then
9        result=`acLookFor "$name"`
10    fi
11    TLOG " ($result)"
12    echo "$result"
13}
14
15bup_try_c_code()
16{
17    local code="$1" tmpdir rc cflags=''
18    if test -z "$code"; then
19        AC_FAIL "No code provided to test compile"
20    fi
21    case "$#" in
22        1) ;;
23        2) cflags="$2" ;;
24        *)
25            AC_FAIL "Invald call to bup_try_c_code" "$@"
26            ;;
27    esac
28    tmpdir="$(mktemp -d "bup-try-c-compile-XXXXXXX")" || exit $?
29    echo "$code" > "$tmpdir/test.c" || exit $?
30    $AC_CC -Wall -Werror $cflags -c -o "$tmpdir/test" "$tmpdir/test.c"
31    rc=$?
32    rm -r "$tmpdir" || exit $?
33    return $rc
34}
35
36TARGET=bup
37
38. ./configure.inc
39
40AC_INIT $TARGET
41
42if ! AC_PROG_CC; then
43    LOG " You need to have a functional C compiler to build $TARGET"
44    exit 1
45fi
46
47MAKE="$(bup_find_prog make "$MAKE")"
48if test -z "$MAKE"; then
49    MAKE="$(bup_find_prog gmake "$GMAKE")"
50fi
51
52if test -z "$MAKE"; then
53    AC_FAIL "ERROR: unable to find make"
54fi
55
56if ! ($MAKE --version | grep "GNU Make"); then
57    AC_FAIL "ERROR: $MAKE is not GNU Make"
58fi
59
60MAKE_VERSION=`$MAKE --version | grep "GNU Make" | awk '{print $3}'`
61if [ -z "$MAKE_VERSION" ]; then
62    AC_FAIL "ERROR: $MAKE --version does not return sensible output?"
63fi
64expr "$MAKE_VERSION" '>=' '3.81' || AC_FAIL "ERROR: $MAKE must be >= version 3.81"
65
66AC_SUB bup_make "$MAKE"
67
68bup_python="$(type -p "$PYTHON")"
69test -z "$bup_python" && bup_python="$(bup_find_prog python3.9 '')"
70test -z "$bup_python" && bup_python="$(bup_find_prog python3.8 '')"
71test -z "$bup_python" && bup_python="$(bup_find_prog python3.7 '')"
72test -z "$bup_python" && bup_python="$(bup_find_prog python3.6 '')"
73test -z "$bup_python" && bup_python="$(bup_find_prog python2.7 '')"
74test -z "$bup_python" && bup_python="$(bup_find_prog python2.6 '')"
75test -z "$bup_python" && bup_python="$(bup_find_prog python2 '')"
76test -z "$bup_python" && bup_python="$(bup_find_prog python '')"
77if test -z "$bup_python"; then
78    AC_FAIL "ERROR: unable to find python"
79else
80    AC_SUB bup_python "$bup_python"
81    AC_SUB bup_python_majver \
82           "$("$bup_python" -c 'import sys; print(sys.version_info[0])')"
83fi
84
85bup_git="$(bup_find_prog git '')"
86if test -z "$bup_git"; then
87    AC_FAIL "ERROR: unable to find git"
88fi
89
90# For stat.
91AC_CHECK_HEADERS sys/stat.h
92AC_CHECK_HEADERS sys/types.h
93
94# For stat and mincore.
95AC_CHECK_HEADERS unistd.h
96
97# For mincore.
98AC_CHECK_HEADERS sys/mman.h
99
100# For FS_IOC_GETFLAGS and FS_IOC_SETFLAGS.
101AC_CHECK_HEADERS linux/fs.h
102AC_CHECK_HEADERS sys/ioctl.h
103
104# On GNU/kFreeBSD utimensat is defined in GNU libc, but won't work.
105if [ -z "$OS_GNU_KFREEBSD" ]; then
106    AC_CHECK_FUNCS utimensat
107fi
108AC_CHECK_FUNCS utimes
109AC_CHECK_FUNCS lutimes
110
111
112builtin_mul_overflow_code="
113#include <stddef.h>
114int main(int argc, char **argv)
115{
116    size_t n = 0, size = 0, total;
117    __builtin_mul_overflow(n, size, &total);
118    return 0;
119}
120"
121
122TLOGN "checking for __builtin_mul_overflow"
123if bup_try_c_code "$builtin_mul_overflow_code"; then
124    AC_DEFINE BUP_HAVE_BUILTIN_MUL_OVERFLOW 1
125    TLOG ' (found)'
126else
127    TLOG ' (not found)'
128fi
129
130
131AC_CHECK_FUNCS mincore
132
133mincore_incore_code="
134#if 0$ac_defined_HAVE_UNISTD_H
135#include <unistd.h>
136#endif
137#if 0$ac_defined_HAVE_SYS_MMAN_H
138#include <sys/mman.h>
139#endif
140int main(int argc, char **argv)
141{
142    if (MINCORE_INCORE)
143      return 0;
144}
145"
146
147mincore_buf_type_code()
148{
149    local vec_type="$1"
150    echo "
151#include <sys/mman.h>
152int main(int argc, char **argv)
153{
154    void *x = 0;
155    $vec_type *buf = 0;
156    return mincore(x, 0, buf);
157}" || exit $?
158}
159
160if test "$ac_defined_HAVE_MINCORE"; then
161    TLOGN "checking for MINCORE_INCORE"
162    if bup_try_c_code "$mincore_incore_code"; then
163        AC_DEFINE BUP_HAVE_MINCORE_INCORE 1
164        TLOG ' (found)'
165    else
166        TLOG ' (not found)'
167    fi
168
169    TLOGN "checking mincore buf type"
170    if bup_try_c_code "$(mincore_buf_type_code char)"; then
171        AC_DEFINE BUP_MINCORE_BUF_TYPE 'char'
172        TLOG ' (char)'
173    elif bup_try_c_code "$(mincore_buf_type_code 'unsigned char')"; then
174        AC_DEFINE BUP_MINCORE_BUF_TYPE 'unsigned char'
175        TLOG ' (unsigned char)'
176    else
177        AC_FAIL "ERROR: unexpected mincore definition; please notify bup-list@googlegroups.com"
178    fi
179fi
180
181
182TLOGN "checking for readline"
183bup_have_readline=''
184bup_readline_includes_in_subdir=''
185bup_readline_via_pkg_config=''
186# We test this specific thing because it should work everywhere and it was
187# a particulary problem on macos (we'd get the wrong includes if we just
188# tested that the includes work).
189readline_test_code='
190  static char *on_completion_entry(const char *text, int state) { return NULL; }
191  void bup_test(void) { rl_completion_entry_function = on_completion_entry; }
192'
193if pkg-config readline; then
194    bup_readline_cflags="$(pkg-config readline --cflags)" || exit $?
195    bup_readline_ldflags="$(pkg-config readline --libs)" || exit $?
196    # It looks like it's not uncommon for pkg-config to provide a -I
197    # that doesn't support the documentation's specified #include
198    # <readline/readline.h>.  See what's really going on.
199    if bup_try_c_code "#include <readline/readline.h> $readline_test_code" \
200                      "$bup_readline_cflags"
201    then
202        bup_have_readline=1
203        bup_readline_includes_in_subdir=1
204    elif bup_try_c_code "#include <readline.h> $readline_test_code" \
205                        "$bup_readline_cflags"
206    then
207        bup_have_readline=1
208    fi
209    if test "$bup_have_readline"; then
210        bup_readline_via_pkg_config=1
211    else
212        bup_readline_cflags=''
213        bup_readline_ldflags=''
214    fi
215fi
216if ! test "$bup_have_readline"; then
217    if bup_try_c_code "#include <readline/readline.h> $readline_test_code"; then
218        bup_readline_ldflags=-lreadline
219        bup_have_readline=1
220        bup_readline_includes_in_subdir=1
221    elif bup_try_c_code "#include <readline.h> $readline_test_code"; then
222        bup_readline_ldflags=-lreadline
223        bup_have_readline=1
224    fi
225fi
226if test "$bup_have_readline"; then
227    AC_DEFINE BUP_HAVE_READLINE 1
228    if test "$bup_readline_includes_in_subdir"; then
229        AC_DEFINE BUP_READLINE_INCLUDES_IN_SUBDIR 1
230    fi
231    if test "$bup_readline_via_pkg_config"; then
232        TLOG ' (yes, pkg-config)'
233    else
234        TLOG ' (yes)'
235    fi
236fi
237
238
239AC_SUB bup_readline_cflags "$bup_readline_cflags"
240AC_SUB bup_readline_ldflags "$bup_readline_ldflags"
241AC_SUB bup_have_readline "$bup_have_readline"
242
243
244AC_CHECK_FIELD stat st_atim sys/types.h sys/stat.h unistd.h
245AC_CHECK_FIELD stat st_mtim sys/types.h sys/stat.h unistd.h
246AC_CHECK_FIELD stat st_ctim sys/types.h sys/stat.h unistd.h
247
248AC_CHECK_FIELD stat st_atimensec sys/types.h sys/stat.h unistd.h
249AC_CHECK_FIELD stat st_mtimensec sys/types.h sys/stat.h unistd.h
250AC_CHECK_FIELD stat st_ctimensec sys/types.h sys/stat.h unistd.h
251
252AC_CHECK_FIELD tm tm_gmtoff time.h
253
254
255orig_ac_cc="$AC_CC"
256orig_libs="$LIBS"
257TLOGN "checking for libacl"
258if pkg-config libacl; then
259    bup_libacl_cflags="$(pkg-config libacl --cflags)"
260    bup_libacl_ldflags="$(pkg-config libacl --libs)"
261    TLOG ' (yes, pkg-config)'
262else
263    bup_libacl_cflags=
264    bup_libacl_ldflags='-lacl'
265    TLOG ' (yes)'
266fi
267AC_CC="$AC_CC${bup_libacl_cflags:+ $bup_libacl_cflags}"
268LIBS="$bup_libacl_ldflags"
269AC_CHECK_HEADERS sys/acl.h
270AC_CHECK_HEADERS acl/libacl.h
271AC_CHECK_FUNCS acl_get_file
272AC_CHECK_FUNCS acl_from_text
273AC_CHECK_FUNCS acl_set_file
274# Note: These are linux specific, but we need them (for now?)
275AC_CHECK_FUNCS acl_extended_file
276AC_CHECK_FUNCS acl_to_any_text
277TLOGN "checking for complete acl support"
278if test "$ac_defined_HAVE_ACL_EXTENDED_FILE"; then
279    bup_have_libacl=1
280    AC_SUB bup_libacl_cflags "$bup_libacl_cflags"
281    AC_SUB bup_libacl_ldflags "$bup_libacl_ldflags"
282    TLOG ' (yes)'
283else
284    bup_have_libacl=
285    AC_SUB bup_have_libacl ''
286    TLOG ' (no)'
287fi
288AC_SUB bup_have_libacl "$bup_have_libacl"
289AC_CC="$orig_ac_cc"
290LIBS="$orig_libs"
291
292
293AC_OUTPUT config.vars
294
295if test -e config.var; then rm -r config.var; fi
296mkdir -p config.var
297echo -n "$MAKE" > config.var/bup-make
298echo -n "$bup_python" > config.var/bup-python
299
300if test -e bin; then rm -r bin; fi
301mkdir -p bin
302(cd bin && ln -s "$bup_python" python)
303
304printf "
305found: python (%q, $("$bup_python" --version 2>&1))
306found: git (%q, ($("$bup_git" --version))
307" \
308       "$bup_python" \
309       "$bup_git" \
310       1>&5
311
312summarize()
313{
314    local found="$1"
315    shift
316    if test "$found"; then
317        TLOG found: "$@"
318    else
319        TLOG not found: "$@"
320    fi
321}
322summarize "$bup_have_readline" 'readline support (e.g. bup ftp)'
323summarize "$bup_have_libacl" 'POSIX ACL support'
324TLOG
325