gnulib-tool: Use the Python implementation by default.
[gnulib.git] / gnulib-tool.py
blob81537c272ca10f7f953b2b8480367634f7ad1884
1 #! /bin/sh
3 # Copyright (C) 2002-2024 Free Software Foundation, Inc.
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <https://www.gnu.org/licenses/>.
19 # This program invokes the Python rewrite of gnulib-tool.
20 # It is meant to behave identically to gnulib-tool, just faster.
22 progname=$0
24 # func_exit STATUS
25 # exits with a given status.
26 # This function needs to be used, rather than 'exit', when a 'trap' handler is
27 # in effect that refers to $?.
28 func_exit ()
30 (exit $1); exit $1
33 # func_fatal_error message
34 # outputs to stderr a fatal error message, and terminates the program.
35 # Input:
36 # - progname name of this program
37 func_fatal_error ()
39 echo "$progname: *** $1" 1>&2
40 echo "$progname: *** Stop." 1>&2
41 func_exit 1
44 # func_readlink SYMLINK
45 # outputs the target of the given symlink.
46 if (type readlink) > /dev/null 2>&1; then
47 func_readlink ()
49 # Use the readlink program from GNU coreutils.
50 readlink "$1"
52 else
53 func_readlink ()
55 # Use two sed invocations. A single sed -n -e 's,^.* -> \(.*\)$,\1,p'
56 # would do the wrong thing if the link target contains " -> ".
57 LC_ALL=C ls -l "$1" | sed -e 's, -> ,#%%#,' | sed -n -e 's,^.*#%%#\(.*\)$,\1,p'
61 # func_gnulib_dir
62 # locates the directory where the gnulib repository lives
63 # Input:
64 # - progname name of this program
65 # Sets variables
66 # - self_abspathname absolute pathname of gnulib-tool
67 # - gnulib_dir absolute pathname of gnulib repository
68 func_gnulib_dir ()
70 case "$progname" in
71 /* | ?:*) self_abspathname="$progname" ;;
72 */*) self_abspathname=`pwd`/"$progname" ;;
74 # Look in $PATH.
75 # Iterate through the elements of $PATH.
76 # We use IFS=: instead of
77 # for d in `echo ":$PATH:" | sed -e 's/:::*/:.:/g' | sed -e 's/:/ /g'`
78 # because the latter does not work when some PATH element contains spaces.
79 # We use a canonicalized $pathx instead of $PATH, because empty PATH
80 # elements are by definition equivalent to '.', however field splitting
81 # according to IFS=: loses empty fields in many shells:
82 # - /bin/sh on OSF/1 and Solaris loses all empty fields (at the
83 # beginning, at the end, and in the middle),
84 # - /bin/sh on IRIX and /bin/ksh on IRIX and OSF/1 lose empty fields
85 # at the beginning and at the end,
86 # - GNU bash, /bin/sh on AIX and HP-UX, and /bin/ksh on AIX, HP-UX,
87 # Solaris lose empty fields at the end.
88 # The 'case' statement is an optimization, to avoid evaluating the
89 # explicit canonicalization command when $PATH contains no empty fields.
90 self_abspathname=
91 if test "$PATH_SEPARATOR" = ";"; then
92 # On Windows, programs are searched in "." before $PATH.
93 pathx=".;$PATH"
94 else
95 # On Unix, we have to convert empty PATH elements to ".".
96 pathx="$PATH"
97 case :$PATH: in
98 *::*)
99 pathx=`echo ":$PATH:" | sed -e 's/:::*/:.:/g' -e 's/^://' -e 's/:\$//'`
101 esac
103 saved_IFS="$IFS"
104 IFS="$PATH_SEPARATOR"
105 for d in $pathx; do
106 IFS="$saved_IFS"
107 test -z "$d" && d=.
108 if test -x "$d/$progname" && test ! -d "$d/$progname"; then
109 self_abspathname="$d/$progname"
110 break
112 done
113 IFS="$saved_IFS"
114 if test -z "$self_abspathname"; then
115 func_fatal_error "could not locate the gnulib-tool program - how did you invoke it?"
118 esac
119 while test -h "$self_abspathname"; do
120 # Resolve symbolic link.
121 linkval=`func_readlink "$self_abspathname"`
122 test -n "$linkval" || break
123 case "$linkval" in
124 /* | ?:* ) self_abspathname="$linkval" ;;
125 * ) self_abspathname=`echo "$self_abspathname" | sed -e 's,/[^/]*$,,'`/"$linkval" ;;
126 esac
127 done
128 gnulib_dir=`echo "$self_abspathname" | sed -e 's,/[^/]*$,,'`
131 func_gnulib_dir
133 # Check the Python version.
134 if (python3 --version) >/dev/null 2>/dev/null; then
135 case `python3 --version 2>&1` in
136 Python\ 3.[0-6] | Python\ 3.[0-6].*)
137 func_fatal_error "python3 is too old (minimum required version is 3.7); try setting GNULIB_TOOL_IMPL=sh" ;;
138 Python\ 3.*)
141 func_fatal_error "python3 version is unsupported" ;;
142 esac
143 else
144 func_fatal_error "python3 not found; try setting GNULIB_TOOL_IMPL=sh"
147 # Tell Python to store the compiled bytecode outside the gnulib directory.
148 if test -z "$PYTHONPYCACHEPREFIX"; then
149 PYTHONPYCACHEPREFIX="${TMPDIR-/tmp}/gnulib-python-cache-${USER-$LOGNAME}"
150 export PYTHONPYCACHEPREFIX
153 profiler_args=
154 # For profiling, cf. <https://docs.python.org/3/library/profile.html>.
155 #profiler_args="-m cProfile -s tottime"
156 exec python3 $profiler_args "$gnulib_dir/.gnulib-tool.py" "$@"