xref: /freebsd/contrib/file/compile (revision 7af41682a96bf7058b82665c33bb9b1bfa079c17)
1#! /bin/sh
2# Wrapper for compilers which do not understand '-c -o'.
3
4scriptversion=2025-02-03.05; # UTC
5
6# Copyright (C) 1999-2025 Free Software Foundation, Inc.
7# Written by Tom Tromey <tromey@cygnus.com>.
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2, or (at your option)
12# any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program.  If not, see <https://www.gnu.org/licenses/>.
21
22# As a special exception to the GNU General Public License, if you
23# distribute this file as part of a program that contains a
24# configuration script generated by Autoconf, you may include it under
25# the same distribution terms that you use for the rest of that program.
26
27# This file is maintained in Automake, please report
28# bugs to <bug-automake@gnu.org> or send patches to
29# <automake-patches@gnu.org>.
30
31nl='
32'
33
34# We need space, tab and new line, in precisely that order.  Quoting is
35# there to prevent tools from complaining about whitespace usage.
36IFS=" ""	$nl"
37
38file_conv=
39
40# func_file_conv build_file unneeded_conversions
41# Convert a $build file to $host form and store it in $file
42# Currently only supports Windows hosts. If the determined conversion
43# type is listed in (the comma separated) UNNEEDED_CONVERSIONS, no
44# conversion will take place.
45func_file_conv ()
46{
47  file=$1
48  case $file in
49    / | /[!/]*) # absolute file, and not a UNC file
50      if test -z "$file_conv"; then
51	# lazily determine how to convert abs files
52	case `uname -s` in
53	  MINGW*)
54	    if test -n "$MSYSTEM" && (cygpath --version) >/dev/null 2>&1; then
55	      # MSYS2 environment.
56	      file_conv=cygwin
57	    else
58	      # Original MinGW environment.
59	      file_conv=mingw
60	    fi
61	    ;;
62	  MSYS*)
63	    # Old MSYS environment, or MSYS2 with 32-bit MSYS2 shell.
64	    file_conv=cygwin
65	    ;;
66	  CYGWIN*)
67	    # Cygwin environment.
68	    file_conv=cygwin
69	    ;;
70	  *)
71	    file_conv=wine
72	    ;;
73	esac
74      fi
75      case $file_conv/,$2, in
76	*,$file_conv,*)
77	  # This is the optimization mentioned above:
78	  # If UNNEEDED_CONVERSIONS contains $file_conv, don't convert.
79	  ;;
80	mingw/*)
81	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
82	  ;;
83	cygwin/*)
84	  file=`cygpath -w "$file" || echo "$file"`
85	  ;;
86	wine/*)
87	  file=`winepath -w "$file" || echo "$file"`
88	  ;;
89      esac
90      ;;
91  esac
92}
93
94# func_cl_dashL linkdir
95# Make cl look for libraries in LINKDIR
96func_cl_dashL ()
97{
98  func_file_conv "$1"
99  if test -z "$lib_path"; then
100    lib_path=$file
101  else
102    lib_path="$lib_path;$file"
103  fi
104  linker_opts="$linker_opts -LIBPATH:$file"
105}
106
107# func_cl_dashl library
108# Do a library search-path lookup for cl
109func_cl_dashl ()
110{
111  lib=$1
112  found=no
113  save_IFS=$IFS
114  IFS=';'
115  for dir in $lib_path $LIB
116  do
117    IFS=$save_IFS
118    if $shared && test -f "$dir/$lib.dll.lib"; then
119      found=yes
120      lib=$dir/$lib.dll.lib
121      break
122    fi
123    if test -f "$dir/$lib.lib"; then
124      found=yes
125      lib=$dir/$lib.lib
126      break
127    fi
128    if test -f "$dir/lib$lib.a"; then
129      found=yes
130      lib=$dir/lib$lib.a
131      break
132    fi
133  done
134  IFS=$save_IFS
135
136  if test "$found" != yes; then
137    lib=$lib.lib
138  fi
139}
140
141# func_cl_wrapper cl arg...
142# Adjust compile command to suit cl
143func_cl_wrapper ()
144{
145  # Assume a capable shell
146  lib_path=
147  shared=:
148  linker_opts=
149  for arg
150  do
151    if test -n "$eat"; then
152      eat=
153    else
154      case $1 in
155	-o)
156	  # configure might choose to run compile as 'compile cc -o foo foo.c'.
157	  eat=1
158	  case $2 in
159	    *.o | *.lo | *.[oO][bB][jJ])
160	      func_file_conv "$2"
161	      set x "$@" -Fo"$file"
162	      shift
163	      ;;
164	    *)
165	      func_file_conv "$2"
166	      set x "$@" -Fe"$file"
167	      shift
168	      ;;
169	  esac
170	  ;;
171	-I)
172	  eat=1
173	  func_file_conv "$2" mingw
174	  set x "$@" -I"$file"
175	  shift
176	  ;;
177	-I*)
178	  func_file_conv "${1#-I}" mingw
179	  set x "$@" -I"$file"
180	  shift
181	  ;;
182	-l)
183	  eat=1
184	  func_cl_dashl "$2"
185	  set x "$@" "$lib"
186	  shift
187	  ;;
188	-l*)
189	  func_cl_dashl "${1#-l}"
190	  set x "$@" "$lib"
191	  shift
192	  ;;
193	-L)
194	  eat=1
195	  func_cl_dashL "$2"
196	  ;;
197	-L*)
198	  func_cl_dashL "${1#-L}"
199	  ;;
200	-static)
201	  shared=false
202	  ;;
203	-Wl,*)
204	  arg=${1#-Wl,}
205	  save_ifs="$IFS"; IFS=','
206	  for flag in $arg; do
207	    IFS="$save_ifs"
208	    linker_opts="$linker_opts $flag"
209	  done
210	  IFS="$save_ifs"
211	  ;;
212	-Xlinker)
213	  eat=1
214	  linker_opts="$linker_opts $2"
215	  ;;
216	-*)
217	  set x "$@" "$1"
218	  shift
219	  ;;
220	*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
221	  func_file_conv "$1"
222	  set x "$@" -Tp"$file"
223	  shift
224	  ;;
225	*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
226	  func_file_conv "$1" mingw
227	  set x "$@" "$file"
228	  shift
229	  ;;
230	*)
231	  set x "$@" "$1"
232	  shift
233	  ;;
234      esac
235    fi
236    shift
237  done
238  if test -n "$linker_opts"; then
239    linker_opts="-link$linker_opts"
240  fi
241  exec "$@" $linker_opts
242  exit 1
243}
244
245eat=
246
247case $1 in
248  '')
249     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
250     exit 1;
251     ;;
252  -h | --h*)
253    cat <<\EOF
254Usage: compile [--help] [--version] PROGRAM [ARGS]
255
256Wrapper for compilers which do not understand '-c -o'.
257Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
258arguments, and rename the output as expected.
259
260If you are trying to build a whole package this is not the
261right script to run: please start by reading the file 'INSTALL'.
262
263Report bugs to <bug-automake@gnu.org>.
264GNU Automake home page: <https://www.gnu.org/software/automake/>.
265General help using GNU software: <https://www.gnu.org/gethelp/>.
266EOF
267    exit $?
268    ;;
269  -v | --v*)
270    echo "compile (GNU Automake) $scriptversion"
271    exit $?
272    ;;
273  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
274  clang-cl | *[/\\]clang-cl | clang-cl.exe | *[/\\]clang-cl.exe | \
275  icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
276    func_cl_wrapper "$@"      # Doesn't return...
277    ;;
278esac
279
280ofile=
281cfile=
282
283for arg
284do
285  if test -n "$eat"; then
286    eat=
287  else
288    case $1 in
289      -o)
290	# configure might choose to run compile as 'compile cc -o foo foo.c'.
291	# So we strip '-o arg' only if arg is an object.
292	eat=1
293	case $2 in
294	  *.o | *.obj)
295	    ofile=$2
296	    ;;
297	  *)
298	    set x "$@" -o "$2"
299	    shift
300	    ;;
301	esac
302	;;
303      *.c)
304	cfile=$1
305	set x "$@" "$1"
306	shift
307	;;
308      *)
309	set x "$@" "$1"
310	shift
311	;;
312    esac
313  fi
314  shift
315done
316
317if test -z "$ofile" || test -z "$cfile"; then
318  # If no '-o' option was seen then we might have been invoked from a
319  # pattern rule where we don't need one.  That is ok -- this is a
320  # normal compilation that the losing compiler can handle.  If no
321  # '.c' file was seen then we are probably linking.  That is also
322  # ok.
323  exec "$@"
324fi
325
326# Name of file we expect compiler to create.
327cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
328
329# Create the lock directory.
330# Note: use '[/\\:.-]' here to ensure that we don't use the same name
331# that we are using for the .o file.  Also, base the name on the expected
332# object file name, since that is what matters with a parallel build.
333lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
334while true; do
335  if mkdir "$lockdir" >/dev/null 2>&1; then
336    break
337  fi
338  sleep 1
339done
340# FIXME: race condition here if user kills between mkdir and trap.
341trap "rmdir '$lockdir'; exit 1" 1 2 15
342
343# Run the compile.
344"$@"
345ret=$?
346
347if test -f "$cofile"; then
348  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
349elif test -f "${cofile}bj"; then
350  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
351fi
352
353rmdir "$lockdir"
354exit $ret
355
356# Local Variables:
357# mode: shell-script
358# sh-indentation: 2
359# eval: (add-hook 'before-save-hook 'time-stamp nil t)
360# time-stamp-start: "scriptversion="
361# time-stamp-format: "%:y-%02m-%02d.%02H"
362# time-stamp-time-zone: "UTC0"
363# time-stamp-end: "; # UTC"
364# End:
365