summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Fiddaman <omnios@citrus-it.co.uk>2018-11-01 10:45:01 +0000
committerAlexander Pyhalov <apyhalov@gmail.com>2018-11-08 12:01:20 +0300
commit1496fbab57b574527f6ec818bbb3d2fc68c40260 (patch)
treee278cca020686b88e57dd8e934160ca8f7840c57
parent249186c6dcae557bd0e0e75c877587f4a8a925ee (diff)
downloadillumos-gfx-drm-1496fbab57b574527f6ec818bbb3d2fc68c40260.tar.gz
9945 gfx-drm should use own cw copy
cw taken from illumos-gate: commit 7ffe8e820e773d6f0f12173b3f476589d34ad1d3 Author: Richard Lowe <richlowe@richlowe.net> Date: Sat Oct 6 01:57:12 2018 +0000 9899 cw(1onbld) should shadow more compilation 9888 cw shouldn't use __unused Reviewed by: Alexander Pyhalov <apyhalov@gmail.com> Reviewed by: Toomas Soome <tsoome@me.com> Reviewed by: Gordon Ross <gordon.w.ross@gmail.com>
-rw-r--r--usr/src/Makefile.master5
-rw-r--r--usr/src/tools/Makefile83
-rw-r--r--usr/src/tools/Makefile.targ34
-rw-r--r--usr/src/tools/Makefile.tools98
-rw-r--r--usr/src/tools/cw/Makefile70
-rw-r--r--usr/src/tools/cw/cw.1onbld220
-rw-r--r--usr/src/tools/cw/cw.c1758
7 files changed, 2248 insertions, 20 deletions
diff --git a/usr/src/Makefile.master b/usr/src/Makefile.master
index 6b0f013..c110481 100644
--- a/usr/src/Makefile.master
+++ b/usr/src/Makefile.master
@@ -107,6 +107,8 @@ CLOSED= $(SRC)/../closed
BUILD_TOOLS= /ws/onnv-tools
ONBLD_TOOLS= $(BUILD_TOOLS)/onbld
+TOOLS= $(SRC)/tools
+TOOLS_PROTO= $(TOOLS)/proto/root_$(MACH)-nd
JAVA_ROOT= /usr/java
@@ -147,6 +149,7 @@ LEX= /usr/ccs/bin/lex
FLEX= /usr/bin/flex
YACC= /usr/ccs/bin/yacc
CPP= /usr/lib/cpp
+MKDIR= /usr/bin/mkdir
JAVAC= $(JAVA_ROOT)/bin/javac
JAVAH= $(JAVA_ROOT)/bin/javah
JAVADOC= $(JAVA_ROOT)/bin/javadoc
@@ -775,7 +778,7 @@ CW_CCC_COMPILERS= $(PRIMARY_CCC:%=--primary %) $(SHADOW_CCCS:%=--shadow %)
# Specify platform compiler versions for languages
# that we use (currently only c and c++).
#
-CW= $(ONBLD_TOOLS)/bin/$(MACH)/cw
+CW= $(TOOLS_PROTO)$(ONBLD_TOOLS)/bin/$(MACH)/cw
BUILD_CC= $(CW) $(CW_CC_COMPILERS) --
BUILD_CCC= $(CW) -C $(CW_CCC_COMPILERS) --
BUILD_CPP= /usr/ccs/lib/cpp
diff --git a/usr/src/tools/Makefile b/usr/src/tools/Makefile
index 55a3a8a..d51e02f 100644
--- a/usr/src/tools/Makefile
+++ b/usr/src/tools/Makefile
@@ -1,33 +1,78 @@
#
-# This file and its contents are supplied under the terms of the
-# Common Development and Distribution License ("CDDL"), version 1.0.
-# You may only use this file in accordance with the terms of version
-# 1.0 of the CDDL.
+# CDDL HEADER START
#
-# A full copy of the text of the CDDL should have accompanied this
-# source. A copy of the CDDL is also available via the Internet at
-# http://www.illumos.org/license/CDDL.
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
-
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
#
-# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+# CDDL HEADER END
#
#
-# Don't want to copy the tools into this skeleton,
-# so just make a link to /opt/onbld
+# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+# Copyright 2016 Toomas Soome <tsoome@me.com>
+# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
+# Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
#
include ../Makefile.master
-all install: proto/root_$(MACH)-nd/opt
+SUBDIRS= cw
+
+include Makefile.tools
+
+ROOTDIRS= \
+ $(ROOTOPT) \
+ $(ROOTONBLD) \
+ $(ROOTONBLD)/bin \
+ $(ROOTONBLD)/bin/$(MACH) \
+ $(ROOTONBLD)/man \
+ $(ROOTONBLD)/man/man1onbld
+
+all := TARGET= install
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+
+.KEEP_STATE:
+
+#
+# Only create directories in the tools proto area when doing an actual
+# build, not a clean or clobber.
+#
+DOROOTDIRS= $(ROOTDIRS)
+clobber:= DOROOTDIRS=
+clean:= DOROOTDIRS=
+
+DOROOTONBLDLIBPY= $(ROOTONBLDLIBPY)
+clobber:= DOROOTONBLDLIBPY=
+clean:= DOROOTONBLDLIBPY=
+
+all install: $(SUBDIRS)
+
+clean: $(SUBDIRS)
+
+clobber: $(SUBDIRS)
+ $(RM) -rf $(TOOLS_PROTO)
+
+.PARALLEL: $(SUBDIRS)
-proto/root_$(MACH)-nd/opt :
- -/usr/bin/mkdir -p proto/root_$(MACH)-nd
- /usr/bin/rm -f $@
- /usr/bin/ln -s /opt $@
+$(SUBDIRS): $$(DOROOTDIRS) FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
-clobber:
- /usr/bin/rm -rf proto
+$(ROOTDIRS):
+ $(MKDIR) -p -m $(DIRMODE) $@
-clean:
+FRC:
diff --git a/usr/src/tools/Makefile.targ b/usr/src/tools/Makefile.targ
new file mode 100644
index 0000000..9b15ccf
--- /dev/null
+++ b/usr/src/tools/Makefile.targ
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# common target definitions for tool builds
+
+clobber: clean
+ -$(RM) $(PROG) $(CLOBBERFILES)
+
+lint_PROG:
+ $(LINT.c) $(PROG).c
+
+lint_SRCS:
+ $(LINT.c) $(SRCS)
diff --git a/usr/src/tools/Makefile.tools b/usr/src/tools/Makefile.tools
new file mode 100644
index 0000000..cd38795
--- /dev/null
+++ b/usr/src/tools/Makefile.tools
@@ -0,0 +1,98 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+# Definitions common to tool source.
+#
+include $(SRC)/Makefile.master
+
+FILEMODE= 0555
+
+TOOLS= $(SRC)/tools
+TOOLS_PROTO= $(TOOLS)/proto/root_$(MACH)-nd
+ROOTOPT= $(TOOLS_PROTO)/opt
+ROOTONBLD= $(ROOTOPT)/onbld
+ROOTONBLDBIN= $(ROOTONBLD)/bin
+ROOTONBLDBINMACH= $(ROOTONBLD)/bin/$(MACH)
+ROOTONBLDETC= $(ROOTONBLD)/etc
+ROOTONBLDLIB= $(ROOTONBLD)/lib
+ROOTONBLDLIBMACH= $(ROOTONBLD)/lib/$(MACH)
+ROOTONBLDLIBMACH64= $(ROOTONBLD)/lib/$(MACH)/64
+ROOTONBLDLIBPERL= $(ROOTONBLD)/lib/perl
+ROOTONBLDLIBPY= $(ROOTONBLD)/lib/python
+ROOTONBLDENV= $(ROOTONBLD)/env
+ROOTONBLDMAN= $(ROOTONBLD)/man
+ROOTONBLDMAN1ONBLD= $(ROOTONBLD)/man/man1onbld
+ROOTONBLDETCABI= $(ROOTONBLD)/etc/abi
+ROOTONBLDETCEXCEPT= $(ROOTONBLD)/etc/exception_lists
+ROOTONBLDSHARE= $(ROOTONBLD)/share
+
+CC = $(NATIVECC)
+CCC = $(NATIVECCC)
+CFLAGS = $(NATIVE_CFLAGS)
+CPPFLAGS= -D_TS_ERRNO
+ELFSIGN_O= $(TRUE)
+LDLIBS=
+LDFLAGS= $(MAPFILE.NES:%=-M%) $(MAPFILE.NED:%=-M%) \
+ $(MAPFILE.PGA:%=-M%)
+
+ROOTONBLDPROG= $(PROG:%=$(ROOTONBLDBIN)/%)
+ROOTONBLDMACHPROG= $(PROG:%=$(ROOTONBLDBINMACH)/%)
+ROOTONBLDSHFILES= $(SHFILES:%=$(ROOTONBLDBIN)/%)
+ROOTONBLDMAKEFILES= $(MAKEFILES:%=$(ROOTONBLDBIN)/%)
+ROOTONBLDMACHSHFILES= $(SHFILES:%=$(ROOTONBLDBINMACH)/%)
+ROOTONBLDMACHBINARIES= $(BINARIES:%=$(ROOTONBLDBINMACH)/%)
+ROOTONBLDETCFILES= $(ETCFILES:%=$(ROOTONBLDETC)/%)
+ROOTONBLDENVFILES= $(ENVFILES:%=$(ROOTONBLDENV)/%)
+ROOTONBLDPERLFILES= $(PERLFILES:%=$(ROOTONBLDBIN)/%)
+ROOTONBLDPERLMODULES= $(PERLMODULES:%=$(ROOTONBLDLIBPERL)/%)
+ROOTONBLDPYFILES= $(PYFILES:%=$(ROOTONBLDBIN)/%)
+ROOTONBLDMAN1ONBLDFILES=$(MAN1ONBLDFILES:%=$(ROOTONBLDMAN1ONBLD)/%)
+ROOTONBLDABIAUDITFILES= $(ABI_AUDITFILES:%=$(ROOTONBLDETCABI)/%)
+ROOTONBLDEXCEPTFILES= $(EXCEPTFILES:%=$(ROOTONBLDETCEXCEPT)/%)
+
+# Break a chicken-and-egg dependency cycle for the tools build
+SCCSCHECK=@echo would sccscheck
+
+$(ROOTONBLDETCABI)/%: %
+ $(INS.file)
+
+$(ROOTONBLDETCEXCEPT)/%: $(CODEMGR_WS)/exception_lists/%
+ $(INS.file)
+
+$(ROOTONBLDBIN)/%: %
+ $(INS.file)
+
+$(ROOTONBLDBINMACH)/%: %
+ $(INS.file)
+
+$(ROOTONBLDETC)/%: %
+ $(INS.file)
+
+$(ROOTONBLDLIBPERL)/%: %
+ $(INS.file)
+
+$(ROOTONBLDMAN1ONBLD)/%: %
+ $(INS.file)
+
+$(ROOTONBLDENV)/%: %
+ $(INS.file)
diff --git a/usr/src/tools/cw/Makefile b/usr/src/tools/cw/Makefile
new file mode 100644
index 0000000..19dd5c0
--- /dev/null
+++ b/usr/src/tools/cw/Makefile
@@ -0,0 +1,70 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2018 Joyent, Inc.
+
+PROG = cw
+
+MAN1ONBLDFILES= cw.1onbld
+
+include ../Makefile.tools
+
+# Bootstrap problem -- we have to build cw before we can use it
+i386_CC= $(SPRO_VROOT)/bin/cc
+sparc_CC= $(SPRO_VROOT)/bin/cc
+$(__GNUC)i386_CC= $(GNUC_ROOT)/bin/gcc
+$(__GNUC)sparc_CC= $(GNUC_ROOT)/bin/gcc
+
+CFLAGS += $(CCVERBOSE)
+
+# Override CFLAGS. This is needed only for bootstrap of cw.
+$(__GNUC)CFLAGS= -O -D__sun -Wall -Wno-unknown-pragmas -Werror \
+ -std=gnu99 -nodefaultlibs
+$(__SUNC)CFLAGS= -xspace -Xa -xildoff -errtags=yes -errwarn=%all \
+ -xc99=%all -W0,-xglobalstatic -v
+
+$(__GNUC)LDLIBS += -lc
+$(__GNUC)LDFLAGS= $(MAPFILE.NES:%=-Wl,-M%)
+
+$(ROOTONBLDMAN1ONBLDFILES) := FILEMODE= 644
+
+# Assume we don't have the install.bin available yet
+INS.file= $(RM) $@; $(CP) $< $(@D); $(CHMOD) $(FILEMODE) $@
+
+.KEEP_STATE:
+
+all: $(PROG) $(MAN1ONBLDFILES)
+
+install: all .WAIT $(ROOTONBLDMACHPROG) $(ROOTONBLDMAN1ONBLDFILES)
+
+lint: lint_PROG
+
+clean:
+
+#
+# Not run by default: bootstrap...
+check:
+ $(ROOTONBLDBINMACH)/mandoc -Tlint -Wwarning $(MAN1ONBLDFILES)
+
+include ../Makefile.targ
diff --git a/usr/src/tools/cw/cw.1onbld b/usr/src/tools/cw/cw.1onbld
new file mode 100644
index 0000000..62800bb
--- /dev/null
+++ b/usr/src/tools/cw/cw.1onbld
@@ -0,0 +1,220 @@
+.\"
+.\" CDDL HEADER START
+.\"
+.\" The contents of this file are subject to the terms of the
+.\" Common Development and Distribution License (the "License").
+.\" You may not use this file except in compliance with the License.
+.\"
+.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+.\" or http://www.opensolaris.org/os/licensing.
+.\" See the License for the specific language governing permissions
+.\" and limitations under the License.
+.\"
+.\" When distributing Covered Code, include this CDDL HEADER in each
+.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+.\" If applicable, add the following below this CDDL HEADER, with the
+.\" fields enclosed by brackets "[]" replaced with your own identifying
+.\" information: Portions Copyright [yyyy] [name of copyright owner]
+.\"
+.\" CDDL HEADER END
+.\"
+.\" Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+.\" Use is subject to license terms.
+.\"
+.\" Copyright 2018 Joyent, Inc.
+.\"
+.Dd September 4, 2018
+.Dt CW 1ONBLD
+.Os
+.Sh NAME
+.Nm cw
+.Nd invoke one or more compilers with argument translation
+.Sh SYNOPSIS
+.Nm cw
+.Op Fl C
+.Op Fl -versions
+.Op Fl -noecho
+.Fl -primary Ar compiler
+.Op Fl -shadow Ar compiler ...
+.Fl -
+.Ar compiler args ...
+.Sh DESCRIPTION
+.Nm cw
+is a facility for invoking one or more compilers, providing translation from
+Sun style arguments as appropriate.
+This allows the use of arbitrary compilers without the need to alter large
+numbers of makefiles.
+A mode called shadow compilation invokes multiple compilers so that warnings
+and errors may be obtained from all of them.
+See
+.Sx SHADOW COMPILATION
+for details.
+This version of cw supports compilers with both Sun Studio 12 and GCC-style
+command lines.
+.Sh ARGUMENTS
+Both the
+.Fl -primary
+and
+.Fl -shadow
+parameters take a
+.Em compiler specification .
+This is a comma-separated list of the form
+.Ar name,executable,style
+Where
+.Ar name
+is a name for the compiler,
+.Ar executable
+is the full path to the compiler executable, and
+.Ar style
+is the style of command-line options the compiler expects, either
+.Em sun
+or
+.Em gnu .
+.Bl -tag -width indent
+.It Fl -primary Ar compiler
+Specify the compiler to be used primarily (that which is used for link-editing
+and pre-processing, and whos objects we deliver).
+.It Fl -shadow Ar compiler
+Specify a shadow compiler, which builds sources for the sake of checking code
+quality and compatibility, but has its output discarded.
+.It Fl -noecho
+Do not echo the actual command line of any compilers invoked.
+.It Fl -versions
+Request from each configured primary and shadow compiler its version
+information.
+.It Fl C
+The sources being compiled are C++. This is necessary as it affects the
+translation of compiler arguments.
+.It Fl -
+Arguments intended for the compilers themselves must be separated from those
+of
+.Nm cw
+by a
+.Fl - .
+.It Fl _name=
+.It Fl _style=
+Parameters intended for the compiler be guarded with options of the form
+.Fl _name=
+and
+.Fl _style=
+Where
+.Em name
+and
+.Em style
+are those passed to
+.Fl -primary
+and
+.Fl -shadow
+this allows certain flags to be passed only to certain classes of compiler.
+.Pp
+For historical reasons, the
+.Fl _style=
+option is also translated such that a style of
+.Em sun
+may use the flag
+.Fl _cc=
+and a style of
+.Em gnu
+may use the flag
+.Fl _gcc= ,
+and when the
+.Fl C
+option is given and C++ is in use the style of
+.Em sun
+may use the flag
+.Fl _CC=
+and the style of
+.Em gnu
+may use the flag
+.Fl _g++= .
+.El
+.Sh SHADOW COMPILATION
+If
+.Fl -shadow
+compilers are specified
+.Nm cw
+will invoke each shadow compiler, with the outputs modified (as well as any
+translation for compiler style) as follows:
+.Bl -enum
+.It
+If
+.Nm cw
+is invoked to link-edit without compilation (the input files are all objects),
+the shadow compiler is not invoked.
+.It
+If the
+.Fl o Ar filename
+option was provided, with or without a separating space, it will be replaced with
+.Fl o Ar tempfile
+.It
+If the option
+.Fl o
+was not provided,
+.Fl o Ar tempfile
+will be added to the end of the argument list used to invoke
+the shadow compilers.
+.El
+When shadow compilation is in effect,
+.Nm cw
+writes to standard error each compiler's standard error output following its
+argument list.
+Messages from the compilers will not be interleaved.
+If
+.Nm cw
+is used to invoke the preprocessor and no output location is specified,
+.Nm cw
+will write to standard output the primary compiler's standard output.
+.Pp
+Because the Sun compilers write intermediate objects to fixed
+filenames in the current directory when instructed to compile and
+link multiple source files via a single command line, it would be
+unsafe to invoke more than one compiler in this fashion.
+Therefore
+.Nm cw
+does not accept multiple source files unless the preprocessor is to be
+invoked.
+An attempt to invoke
+.Nm cw
+in this manner will result in an error.
+.Sh ARGUMENT TRANSLATION
+If the compiler to be invoked is a GNU-style C or C++ compiler, a set of
+default flags is added to the beginning of the argument list, and the
+remaining arguments are translated to their closest appropriate
+semantic equivalents and passed in the same order as their
+counterparts given to
+.Nm cw .
+See the comments at the head of
+.Pa usr/src/tools/cw/cw.c
+for a detailed list of translations.
+.Sh ENVIRONMENT
+.Bl -tag -width indent
+.It CW_SHADOW_SERIAL
+If this variable is set in the environment, invoke the primary compiler, wait
+for it to complete, then invoke the shadow compilers.
+Normally the primary and shadow compilers are invoked in parallel.
+.It CW_NO_EXEC
+f this variable is set in the environment, write the usual output to
+standard error but do not actually invoke any compiler.
+This is useful for debugging the translation engine.
+.El
+.Sh EXIT STATUS
+The following exit status values are returned:
+.Bl -tag -width indent
+.It 0
+The primary compiler, and shadow compilers if invoked, all completed
+successfully.
+.It >0
+A usage error occurred, or one or more compilers returned a nonzero
+exit status.
+.El
+.Sh SEE ALSO
+.Xr cc 1 ,
+.Xr CC 1 ,
+.Xr gcc 1
+.Sh BUGS
+The translations provided for gcc are not always exact and in some cases
+reflect local policy rather than actual equivalence.
+.Pp
+Additional compiler types should be supported.
+.Pp
+The translation engine is hacky.
diff --git a/usr/src/tools/cw/cw.c b/usr/src/tools/cw/cw.c
new file mode 100644
index 0000000..91d6207
--- /dev/null
+++ b/usr/src/tools/cw/cw.c
@@ -0,0 +1,1758 @@
+
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2018, Richard Lowe.
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Wrapper for the GNU C compiler to make it accept the Sun C compiler
+ * arguments where possible.
+ *
+ * Since the translation is inexact, this is something of a work-in-progress.
+ *
+ */
+
+/* If you modify this file, you must increment CW_VERSION */
+#define CW_VERSION "3.0"
+
+/*
+ * -# Verbose mode
+ * -### Show compiler commands built by driver, no compilation
+ * -A<name[(tokens)]> Preprocessor predicate assertion
+ * -B<[static|dynamic]> Specify dynamic or static binding
+ * -C Prevent preprocessor from removing comments
+ * -c Compile only - produce .o files, suppress linking
+ * -cg92 Alias for -xtarget=ss1000
+ * -D<name[=token]> Associate name with token as if by #define
+ * -d[y|n] dynamic [-dy] or static [-dn] option to linker
+ * -E Compile source through preprocessor only, output to stdout
+ * -erroff=<t> Suppress warnings specified by tags t(%none, %all, <tag list>)
+ * -errtags=<a> Display messages with tags a(no, yes)
+ * -errwarn=<t> Treats warnings specified by tags t(%none, %all, <tag list>)
+ * as errors
+ * -fast Optimize using a selection of options
+ * -fd Report old-style function definitions and declarations
+ * -fnonstd Initialize floating-point hardware to non-standard preferences
+ * -fns[=<yes|no>] Select non-standard floating point mode
+ * -fprecision=<p> Set FP rounding precision mode p(single, double, extended)
+ * -fround=<r> Select the IEEE rounding mode in effect at startup
+ * -fsimple[=<n>] Select floating-point optimization preferences <n>
+ * -fsingle Use single-precision arithmetic (-Xt and -Xs modes only)
+ * -ftrap=<t> Select floating-point trapping mode in effect at startup
+ * -fstore force floating pt. values to target precision on assignment
+ * -G Build a dynamic shared library
+ * -g Compile for debugging
+ * -H Print path name of each file included during compilation
+ * -h <name> Assign <name> to generated dynamic shared library
+ * -I<dir> Add <dir> to preprocessor #include file search path
+ * -i Passed to linker to ignore any LD_LIBRARY_PATH setting
+ * -keeptmp Keep temporary files created during compilation
+ * -L<dir> Pass to linker to add <dir> to the library search path
+ * -l<name> Link with library lib<name>.a or lib<name>.so
+ * -mc Remove duplicate strings from .comment section of output files
+ * -mr Remove all strings from .comment section of output files
+ * -mr,"string" Remove all strings and append "string" to .comment section
+ * -mt Specify options needed when compiling multi-threaded code
+ * -native Find available processor, generate code accordingly
+ * -nofstore Do not force floating pt. values to target precision
+ * on assignment
+ * -norunpath Do not build in a runtime path for shared libraries
+ * -O Use default optimization level (-xO2 or -xO3. Check man page.)
+ * -o <outputfile> Set name of output file to <outputfile>
+ * -P Compile source through preprocessor only, output to .i file
+ * -p Compile for profiling with prof
+ * -Q[y|n] Emit/don't emit identification info to output file
+ * -R<dir[:dir]> Build runtime search path list into executable
+ * -S Compile and only generate assembly code (.s)
+ * -s Strip symbol table from the executable file
+ * -t Turn off duplicate symbol warnings when linking
+ * -U<name> Delete initial definition of preprocessor symbol <name>
+ * -V Report version number of each compilation phase
+ * -v Do stricter semantic checking
+ * -W<c>,<arg> Pass <arg> to specified component <c> (a,l,m,p,0,2,h,i,u)
+ * -w Suppress compiler warning messages
+ * -Xa Compile assuming ANSI C conformance, allow K & R extensions
+ * (default mode)
+ * -Xs Compile assuming (pre-ANSI) K & R C style code
+ * -Xt Compile assuming K & R conformance, allow ANSI C
+ * -xarch=<a> Specify target architecture instruction set
+ * -xbuiltin[=<b>] When profitable inline, or substitute intrinisic functions
+ * for system functions, b={%all,%none}
+ * -xCC Accept C++ style comments
+ * -xchip=<c> Specify the target processor for use by the optimizer
+ * -xcode=<c> Generate different code for forming addresses
+ * -xcrossfile[=<n>] Enable optimization and inlining across source files,
+ * n={0|1}
+ * -xe Perform only syntax/semantic checking, no code generation
+ * -xF Compile for later mapfile reordering or unused section
+ * elimination
+ * -xhelp=<f> Display on-line help information f(flags, readme, errors)
+ * -xildoff Cancel -xildon
+ * -xildon Enable use of the incremental linker, ild
+ * -xinline=[<a>,...,<a>] Attempt inlining of specified user routines,
+ * <a>={%auto,func,no%func}
+ * -xlibmieee Force IEEE 754 return values for math routines in
+ * exceptional cases
+ * -xlibmil Inline selected libm math routines for optimization
+ * -xlic_lib=sunperf Link in the Sun supplied performance libraries
+ * -xlicinfo Show license server information
+ * -xmaxopt=[off,1,2,3,4,5] maximum optimization level allowed on #pragma opt
+ * -xO<n> Generate optimized code (n={1|2|3|4|5})
+ * -xP Print prototypes for function definitions
+ * -xprofile=<p> Collect data for a profile or use a profile to optimize
+ * <p>={{collect,use}[:<path>],tcov}
+ * -xregs=<r> Control register allocation
+ * -xs Allow debugging without object (.o) files
+ * -xsb Compile for use with the WorkShop source browser
+ * -xsbfast Generate only WorkShop source browser info, no compilation
+ * -xsfpconst Represent unsuffixed floating point constants as single
+ * precision
+ * -xspace Do not do optimizations that increase code size
+ * -xstrconst Place string literals into read-only data segment
+ * -xtarget=<t> Specify target system for optimization
+ * -xtemp=<dir> Set directory for temporary files to <dir>
+ * -xtime Report the execution time for each compilation phase
+ * -xunroll=n Enable unrolling loops n times where possible
+ * -Y<c>,<dir> Specify <dir> for location of component <c> (a,l,m,p,0,h,i,u)
+ * -YA,<dir> Change default directory searched for components
+ * -YI,<dir> Change default directory searched for include files
+ * -YP,<dir> Change default directory for finding libraries files
+ * -YS,<dir> Change default directory for startup object files
+ */
+
+/*
+ * Translation table:
+ */
+/*
+ * -# -v
+ * -### error
+ * -A<name[(tokens)]> pass-thru
+ * -B<[static|dynamic]> pass-thru (syntax error for anything else)
+ * -C pass-thru
+ * -c pass-thru
+ * -cg92 -m32 -mcpu=v8 -mtune=supersparc (SPARC only)
+ * -D<name[=token]> pass-thru
+ * -dy or -dn -Wl,-dy or -Wl,-dn
+ * -E pass-thru
+ * -erroff=E_EMPTY_TRANSLATION_UNIT ignore
+ * -errtags=%all -Wall
+ * -errwarn=%all -Werror else -Wno-error
+ * -fast error
+ * -fd error
+ * -fnonstd error
+ * -fns[=<yes|no>] error
+ * -fprecision=<p> error
+ * -fround=<r> error
+ * -fsimple[=<n>] error
+ * -fsingle[=<n>] error
+ * -ftrap=<t> error
+ * -fstore error
+ * -G pass-thru
+ * -g pass-thru
+ * -H pass-thru
+ * -h <name> pass-thru
+ * -I<dir> pass-thru
+ * -i pass-thru
+ * -keeptmp -save-temps
+ * -L<dir> pass-thru
+ * -l<name> pass-thru
+ * -mc error
+ * -mr error
+ * -mr,"string" error
+ * -mt -D_REENTRANT
+ * -native error
+ * -nofstore error
+ * -nolib -nodefaultlibs
+ * -norunpath ignore
+ * -O -O1 (Check the man page to be certain)
+ * -o <outputfile> pass-thru
+ * -P -E -o filename.i (or error)
+ * -p pass-thru
+ * -Q[y|n] error
+ * -R<dir[:dir]> pass-thru
+ * -S pass-thru
+ * -s -Wl,-s
+ * -t -Wl,-t
+ * -U<name> pass-thru
+ * -V --version
+ * -v -Wall
+ * -Wa,<arg> pass-thru
+ * -Wp,<arg> pass-thru except -xc99=<a>
+ * -Wl,<arg> pass-thru
+ * -W{m,0,2,h,i,u> error/ignore
+ * -xmodel=kernel -ffreestanding -mcmodel=kernel -mno-red-zone
+ * -Wu,-save_args -msave-args
+ * -w pass-thru
+ * -Xa -std=iso9899:199409 or -ansi
+ * -Xt error
+ * -Xs -traditional -std=c89
+ * -xarch=<a> table
+ * -xbuiltin[=<b>] -fbuiltin (-fno-builtin otherwise)
+ * -xCC ignore
+ * -xchip=<c> table
+ * -xcode=<c> table
+ * -xdebugformat=<format> ignore (always use dwarf-2 for gcc)
+ * -xcrossfile[=<n>] ignore
+ * -xe error
+ * -xF error
+ * -xhelp=<f> error
+ * -xildoff ignore
+ * -xildon ignore
+ * -xinline ignore
+ * -xlibmieee error
+ * -xlibmil error
+ * -xlic_lib=sunperf error
+ * -xmaxopt=[...] error
+ * -xO<n> -O<n>
+ * -xP error
+ * -xprofile=<p> error
+ * -xregs=<r> table
+ * -xs error
+ * -xsb error
+ * -xsbfast error
+ * -xsfpconst error
+ * -xspace ignore (-not -Os)
+ * -xstrconst ignore
+ * -xtarget=<t> table
+ * -xtemp=<dir> error
+ * -xtime error
+ * -xtransition -Wtransition
+ * -xunroll=n error
+ * -W0,-xdbggen=no%usedonly -fno-eliminate-unused-debug-symbols
+ * -fno-eliminate-unused-debug-types
+ * -Y<c>,<dir> error
+ * -YA,<dir> error
+ * -YI,<dir> -nostdinc -I<dir>
+ * -YP,<dir> error
+ * -YS,<dir> error
+ */
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+
+#define CW_F_CXX 0x01
+#define CW_F_SHADOW 0x02
+#define CW_F_EXEC 0x04
+#define CW_F_ECHO 0x08
+#define CW_F_XLATE 0x10
+#define CW_F_PROG 0x20
+
+typedef enum cw_op {
+ CW_O_NONE = 0,
+ CW_O_PREPROCESS,
+ CW_O_COMPILE,
+ CW_O_LINK
+} cw_op_t;
+
+struct aelist {
+ struct ae {
+ struct ae *ae_next;
+ char *ae_arg;
+ } *ael_head, *ael_tail;
+ int ael_argc;
+};
+
+typedef enum {
+ GNU,
+ SUN
+} compiler_style_t;
+
+typedef struct {
+ char *c_name;
+ char *c_path;
+ compiler_style_t c_style;
+} cw_compiler_t;
+
+typedef struct cw_ictx {
+ struct cw_ictx *i_next;
+ cw_compiler_t *i_compiler;
+ struct aelist *i_ae;
+ uint32_t i_flags;
+ int i_oldargc;
+ char **i_oldargv;
+ pid_t i_pid;
+ char *i_discard;
+ char *i_stderr;
+} cw_ictx_t;
+
+/*
+ * Status values to indicate which Studio compiler and associated
+ * flags are being used.
+ */
+#define M32 0x01 /* -m32 - only on Studio 12 */
+#define M64 0x02 /* -m64 - only on Studio 12 */
+#define SS11 0x100 /* Studio 11 */
+#define SS12 0x200 /* Studio 12 */
+
+#define TRANS_ENTRY 5
+/*
+ * Translation table definition for the -xarch= flag. The "x_arg"
+ * value is translated into the appropriate gcc flags according
+ * to the values in x_trans[n]. The x_flags indicates what compiler
+ * is being used and what flags have been set via the use of
+ * "x_arg".
+ */
+typedef struct xarch_table {
+ char *x_arg;
+ int x_flags;
+ char *x_trans[TRANS_ENTRY];
+} xarch_table_t;
+
+/*
+ * The translation table for the -xarch= flag used in the Studio compilers.
+ */
+static const xarch_table_t xtbl[] = {
+#if defined(__x86)
+ { "generic", SS11, {NULL} },
+ { "generic64", (SS11|M64), { "-m64", "-mtune=opteron" } },
+ { "amd64", (SS11|M64), { "-m64", "-mtune=opteron" } },
+ { "386", SS11, { "-march=i386" } },
+ { "pentium_pro", SS11, { "-march=pentiumpro" } },
+ { "sse", SS11, { "-msse", "-mfpmath=sse" } },
+ { "sse2", SS11, { "-msse2", "-mfpmath=sse" } },
+#elif defined(__sparc)
+ { "generic", (SS11|M32), { "-m32", "-mcpu=v8" } },
+ { "generic64", (SS11|M64), { "-m64", "-mcpu=v9" } },
+ { "v8", (SS11|M32), { "-m32", "-mcpu=v8", "-mno-v8plus" } },
+ { "v8plus", (SS11|M32), { "-m32", "-mcpu=v9", "-mv8plus" } },
+ { "v8plusa", (SS11|M32), { "-m32", "-mcpu=ultrasparc", "-mv8plus",
+ "-mvis" } },
+ { "v8plusb", (SS11|M32), { "-m32", "-mcpu=ultrasparc3", "-mv8plus",
+ "-mvis" } },
+ { "v9", (SS11|M64), { "-m64", "-mcpu=v9" } },
+ { "v9a", (SS11|M64), { "-m64", "-mcpu=ultrasparc", "-mvis" } },
+ { "v9b", (SS11|M64), { "-m64", "-mcpu=ultrasparc3", "-mvis" } },
+ { "sparc", SS12, { "-mcpu=v9", "-mv8plus" } },
+ { "sparcvis", SS12, { "-mcpu=ultrasparc", "-mvis" } },
+ { "sparcvis2", SS12, { "-mcpu=ultrasparc3", "-mvis" } }
+#endif
+};
+
+static int xtbl_size = sizeof (xtbl) / sizeof (xarch_table_t);
+
+static const char *xchip_tbl[] = {
+#if defined(__x86)
+ "386", "-mtune=i386", NULL,
+ "486", "-mtune=i486", NULL,
+ "pentium", "-mtune=pentium", NULL,
+ "pentium_pro", "-mtune=pentiumpro", NULL,
+#elif defined(__sparc)
+ "super", "-mtune=supersparc", NULL,
+ "ultra", "-mtune=ultrasparc", NULL,
+ "ultra3", "-mtune=ultrasparc3", NULL,
+#endif
+ NULL, NULL
+};
+
+static const char *xcode_tbl[] = {
+#if defined(__sparc)
+ "abs32", "-fno-pic", "-mcmodel=medlow", NULL,
+ "abs44", "-fno-pic", "-mcmodel=medmid", NULL,
+ "abs64", "-fno-pic", "-mcmodel=medany", NULL,
+ "pic13", "-fpic", NULL,
+ "pic32", "-fPIC", NULL,
+#endif
+ NULL, NULL
+};
+
+static const char *xtarget_tbl[] = {
+#if defined(__x86)
+ "pentium_pro", "-march=pentiumpro", NULL,
+#endif /* __x86 */
+ NULL, NULL
+};
+
+static const char *xregs_tbl[] = {
+#if defined(__sparc)
+ "appl", "-mapp-regs", NULL,
+ "no%appl", "-mno-app-regs", NULL,
+ "float", "-mfpu", NULL,
+ "no%float", "-mno-fpu", NULL,
+#endif /* __sparc */
+ NULL, NULL
+};
+
+static void
+nomem(void)
+{
+ errx(1, "out of memory");
+}
+
+static void
+newae(struct aelist *ael, const char *arg)
+{
+ struct ae *ae;
+
+ if ((ae = calloc(sizeof (*ae), 1)) == NULL)
+ nomem();
+ ae->ae_arg = strdup(arg);
+ if (ael->ael_tail == NULL)
+ ael->ael_head = ae;
+ else
+ ael->ael_tail->ae_next = ae;
+ ael->ael_tail = ae;
+ ael->ael_argc++;
+}
+
+static cw_ictx_t *
+newictx(void)
+{
+ cw_ictx_t *ctx = calloc(sizeof (cw_ictx_t), 1);
+ if (ctx)
+ if ((ctx->i_ae = calloc(sizeof (struct aelist), 1)) == NULL) {
+ free(ctx);
+ return (NULL);
+ }
+
+ return (ctx);
+}
+
+static void
+error(const char *arg)
+{
+ errx(2, "error: mapping failed at or near arg '%s'", arg);
+}
+
+/*
+ * Add the current favourite set of warnings to the gcc invocation.
+ */
+static void
+warnings(struct aelist *h)
+{
+ static int warningsonce;
+
+ if (warningsonce++)
+ return;
+
+ /*
+ * Enable as many warnings as exist, then disable those that we never
+ * ever want.
+ */
+ newae(h, "-Wall");
+ newae(h, "-Wextra");
+}
+
+static void
+optim_disable(struct aelist *h, int level)
+{
+ if (level >= 2) {
+ newae(h, "-fno-strict-aliasing");
+ newae(h, "-fno-unit-at-a-time");
+ newae(h, "-fno-optimize-sibling-calls");
+ }
+}
+
+static void
+Xsmode(struct aelist *h)
+{
+ static int xsonce;
+
+ if (xsonce++)
+ return;
+
+ newae(h, "-traditional");
+ newae(h, "-traditional-cpp");
+}
+
+static void
+usage()
+{
+ extern char *__progname;
+ (void) fprintf(stderr,
+ "usage: %s [-C] [--versions] --primary <compiler> "
+ "[--shadow <compiler>]... -- cflags...\n",
+ __progname);
+ (void) fprintf(stderr, "compilers take the form: name,path,style\n"
+ " - name: a unique name usable in flag specifiers\n"
+ " - path: path to the compiler binary\n"
+ " - style: the style of flags expected: either sun or gnu\n");
+ exit(2);
+}
+
+static int
+xlate_xtb(struct aelist *h, const char *xarg)
+{
+ int i, j;
+
+ for (i = 0; i < xtbl_size; i++) {
+ if (strcmp(xtbl[i].x_arg, xarg) == 0)
+ break;
+ }
+
+ /*
+ * At the end of the table and so no matching "arg" entry
+ * found and so this must be a bad -xarch= flag.
+ */
+ if (i == xtbl_size)
+ error(xarg);
+
+ for (j = 0; j < TRANS_ENTRY; j++) {
+ if (xtbl[i].x_trans[j] != NULL)
+ newae(h, xtbl[i].x_trans[j]);
+ else
+ break;
+ }
+ return (xtbl[i].x_flags);
+
+}
+
+static void
+xlate(struct aelist *h, const char *xarg, const char **table)
+{
+ while (*table != NULL && strcmp(xarg, *table) != 0) {
+ while (*table != NULL)
+ table++;
+ table++;
+ }
+
+ if (*table == NULL)
+ error(xarg);
+
+ table++;
+
+ while (*table != NULL) {
+ newae(h, *table);
+ table++;
+ }
+}
+
+/*
+ * The compiler wants the output file to end in appropriate extension. If
+ * we're generating a name from whole cloth (path == NULL), we assume that
+ * extension to be .o, otherwise we match the extension of the caller.
+ */
+static char *
+discard_file_name(const char *path)
+{
+ char *ret, *ext, *file;
+
+ if (path == NULL) {
+ ext = ".o";
+ } else {
+ ext = strrchr(path, '.');
+ }
+
+ if ((ret = calloc(MAXPATHLEN, sizeof (char))) == NULL)
+ nomem();
+
+ if ((file = tempnam(NULL, ".cw")) == NULL)
+ nomem();
+
+ (void) strlcpy(ret, file, MAXPATHLEN);
+ if (ext != NULL)
+ (void) strlcat(ret, ext, MAXPATHLEN);
+ free(file);
+ return (ret);
+}
+
+static void
+do_gcc(cw_ictx_t *ctx)
+{
+ int c;
+ int nolibc = 0;
+ int in_output = 0, seen_o = 0, c_files = 0;
+ cw_op_t op = CW_O_LINK;
+ char *model = NULL;
+ char *nameflag;
+ int mflag = 0;
+
+ if (ctx->i_flags & CW_F_PROG) {
+ newae(ctx->i_ae, "--version");
+ return;
+ }
+
+ newae(ctx->i_ae, "-fident");
+ newae(ctx->i_ae, "-finline");
+ newae(ctx->i_ae, "-fno-inline-functions");
+ newae(ctx->i_ae, "-fno-builtin");
+ newae(ctx->i_ae, "-fno-asm");
+ newae(ctx->i_ae, "-fdiagnostics-show-option");
+ newae(ctx->i_ae, "-nodefaultlibs");
+
+#if defined(__sparc)
+ /*
+ * The SPARC ldd and std instructions require 8-byte alignment of
+ * their address operand. gcc correctly uses them only when the
+ * ABI requires 8-byte alignment; unfortunately we have a number of
+ * pieces of buggy code that doesn't conform to the ABI. This
+ * flag makes gcc work more like Studio with -xmemalign=4.
+ */
+ newae(ctx->i_ae, "-mno-integer-ldd-std");
+#endif
+
+ /*
+ * This is needed because 'u' is defined
+ * under a conditional on 'sun'. Should
+ * probably just remove the conditional,
+ * or make it be dependent on '__sun'.
+ *
+ * -Dunix is also missing in enhanced ANSI mode
+ */
+ newae(ctx->i_ae, "-D__sun");
+
+ if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
+ nomem();
+
+ /*
+ * Walk the argument list, translating as we go ..
+ */
+ while (--ctx->i_oldargc > 0) {
+ char *arg = *++ctx->i_oldargv;
+ size_t arglen = strlen(arg);
+
+ if (*arg == '-') {
+ arglen--;
+ } else {
+ /*
+ * Discard inline files that gcc doesn't grok
+ */
+ if (!in_output && arglen > 3 &&
+ strcmp(arg + arglen - 3, ".il") == 0)
+ continue;
+
+ if (!in_output && arglen > 2 &&
+ arg[arglen - 2] == '.' &&
+ (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' ||
+ arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i'))
+ c_files++;
+
+ /*
+ * Otherwise, filenames and partial arguments
+ * are passed through for gcc to chew on. However,
+ * output is always discarded for the secondary
+ * compiler.
+ */
+ if ((ctx->i_flags & CW_F_SHADOW) && in_output) {
+ ctx->i_discard = discard_file_name(arg);
+ newae(ctx->i_ae, ctx->i_discard);
+ } else {
+ newae(ctx->i_ae, arg);
+ }
+ in_output = 0;
+ continue;
+ }
+
+ if (ctx->i_flags & CW_F_CXX) {
+ if (strncmp(arg, "-_g++=", 6) == 0) {
+ newae(ctx->i_ae, strchr(arg, '=') + 1);
+ continue;
+ }
+ if (strncmp(arg, "-compat=", 8) == 0) {
+ /* discard -compat=4 and -compat=5 */
+ continue;
+ }
+ if (strcmp(arg, "-Qoption") == 0) {
+ /* discard -Qoption and its two arguments */
+ if (ctx->i_oldargc < 3)
+ error(arg);
+ ctx->i_oldargc -= 2;
+ ctx->i_oldargv += 2;
+ continue;
+ }
+ if (strcmp(arg, "-xwe") == 0) {
+ /* turn warnings into errors */
+ newae(ctx->i_ae, "-Werror");
+ continue;
+ }
+ if (strcmp(arg, "-norunpath") == 0) {
+ /* gcc has no corresponding option */
+ continue;
+ }
+ if (strcmp(arg, "-nolib") == 0) {
+ /* -nodefaultlibs is on by default */
+ nolibc = 1;
+ continue;
+ }
+#if defined(__sparc)
+ if (strcmp(arg, "-cg92") == 0) {
+ mflag |= xlate_xtb(ctx->i_ae, "v8");
+ xlate(ctx->i_ae, "super", xchip_tbl);
+ continue;
+ }
+#endif /* __sparc */
+ }
+
+ switch ((c = arg[1])) {
+ case '_':
+ if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) ||
+ (strncmp(arg, "-_gcc=", 6) == 0) ||
+ (strncmp(arg, "-_gnu=", 6) == 0)) {
+ newae(ctx->i_ae, strchr(arg, '=') + 1);
+ }
+ break;
+ case '#':
+ if (arglen == 1) {
+ newae(ctx->i_ae, "-v");
+ break;
+ }
+ error(arg);
+ break;
+ case 'f':
+ if ((strcmp(arg, "-fpic") == 0) ||
+ (strcmp(arg, "-fPIC") == 0)) {
+ newae(ctx->i_ae, arg);
+ break;
+ }
+ error(arg);
+ break;
+ case 'g':
+ newae(ctx->i_ae, "-gdwarf-2");
+ break;
+ case 'E':
+ if (arglen == 1) {
+ newae(ctx->i_ae, "-xc");
+ newae(ctx->i_ae, arg);
+ op = CW_O_PREPROCESS;
+ nolibc = 1;
+ break;
+ }
+ error(arg);
+ break;
+ case 'c':
+ case 'S':
+ if (arglen == 1) {
+ op = CW_O_COMPILE;
+ nolibc = 1;
+ }
+ /* FALLTHROUGH */
+ case 'C':
+ case 'H':
+ case 'p':
+ if (arglen == 1) {
+ newae(ctx->i_ae, arg);
+ break;
+ }
+ error(arg);
+ break;
+ case 'A':
+ case 'h':
+ case 'I':
+ case 'i':
+ case 'L':
+ case 'l':
+ case 'R':
+ case 'U':
+ case 'u':
+ case 'w':
+ newae(ctx->i_ae, arg);
+ break;
+ case 'o':
+ seen_o = 1;
+ if (arglen == 1) {
+ in_output = 1;
+ newae(ctx->i_ae, arg);
+ } else if (ctx->i_flags & CW_F_SHADOW) {
+ newae(ctx->i_ae, "-o");
+ ctx->i_discard = discard_file_name(arg);
+ newae(ctx->i_ae, ctx->i_discard);
+ } else {
+ newae(ctx->i_ae, arg);
+ }
+ break;
+ case 'D':
+ newae(ctx->i_ae, arg);
+ /*
+ * XXX Clearly a hack ... do we need _KADB too?
+ */
+ if (strcmp(arg, "-D_KERNEL") == 0 ||
+ strcmp(arg, "-D_BOOT") == 0)
+ newae(ctx->i_ae, "-ffreestanding");
+ break;
+ case 'd':
+ if (arglen == 2) {
+ if (strcmp(arg, "-dy") == 0) {
+ newae(ctx->i_ae, "-Wl,-dy");
+ break;
+ }
+ if (strcmp(arg, "-dn") == 0) {
+ newae(ctx->i_ae, "-Wl,-dn");
+ break;
+ }
+ }
+ if (strcmp(arg, "-dalign") == 0) {
+ /*
+ * -dalign forces alignment in some cases;
+ * gcc does not need any flag to do this.
+ */
+ break;
+ }
+ error(arg);
+ break;
+ case 'e':
+ if (strcmp(arg,
+ "-erroff=E_EMPTY_TRANSLATION_UNIT") == 0) {
+ /*
+ * Accept but ignore this -- gcc doesn't
+ * seem to complain about empty translation
+ * units
+ */
+ break;
+ }
+ /* XX64 -- ignore all -erroff= options, for now */
+ if (strncmp(arg, "-erroff=", 8) == 0)
+ break;
+ if (strcmp(arg, "-errtags=yes") == 0) {
+ warnings(ctx->i_ae);
+ break;
+ }
+ if (strcmp(arg, "-errwarn=%all") == 0) {
+ newae(ctx->i_ae, "-Werror");
+ break;
+ }
+ error(arg);
+ break;
+ case 'G':
+ newae(ctx->i_ae, "-shared");
+ nolibc = 1;
+ break;
+ case 'k':
+ if (strcmp(arg, "-keeptmp") == 0) {
+ newae(ctx->i_ae, "-save-temps");
+ break;
+ }
+ error(arg);
+ break;
+ case 'm':
+ if (strcmp(arg, "-mt") == 0) {
+ newae(ctx->i_ae, "-D_REENTRANT");
+ break;
+ }
+ if (strcmp(arg, "-m64") == 0) {
+ newae(ctx->i_ae, "-m64");
+#if defined(__x86)
+ newae(ctx->i_ae, "-mtune=opteron");
+#endif
+ mflag |= M64;
+ break;
+ }
+ if (strcmp(arg, "-m32") == 0) {
+ newae(ctx->i_ae, "-m32");
+ mflag |= M32;
+ break;
+ }
+ error(arg);
+ break;
+ case 'B': /* linker options */
+ case 'M':
+ case 'z':
+ {
+ char *opt;
+ size_t len;
+ char *s;
+
+ if (arglen == 1) {
+ opt = *++ctx->i_oldargv;
+ if (opt == NULL || *opt == '\0')
+ error(arg);
+ ctx->i_oldargc--;
+ } else {
+ opt = arg + 2;
+ }
+ len = strlen(opt) + 7;
+ if ((s = malloc(len)) == NULL)
+ nomem();
+ (void) snprintf(s, len, "-Wl,-%c%s", c, opt);
+ newae(ctx->i_ae, s);
+ free(s);
+ }
+ break;
+ case 'O':
+ if (arglen == 1) {
+ newae(ctx->i_ae, "-O");
+ break;
+ }
+ error(arg);
+ break;
+ case 'P':
+ /*
+ * We could do '-E -o filename.i', but that's hard,
+ * and we don't need it for the case that's triggering
+ * this addition. We'll require the user to specify
+ * -o in the Makefile. If they don't they'll find out
+ * in a hurry.
+ */
+ newae(ctx->i_ae, "-E");
+ op = CW_O_PREPROCESS;
+ nolibc = 1;
+ break;
+ case 's':
+ if (arglen == 1) {
+ newae(ctx->i_ae, "-Wl,-s");
+ break;
+ }
+ error(arg);
+ break;
+ case 't':
+ if (arglen == 1) {
+ newae(ctx->i_ae, "-Wl,-t");
+ break;
+ }
+ error(arg);
+ break;
+ case 'V':
+ if (arglen == 1) {
+ ctx->i_flags &= ~CW_F_ECHO;
+ newae(ctx->i_ae, "--version");
+ break;
+ }
+ error(arg);
+ break;
+ case 'v':
+ if (arglen == 1) {
+ warnings(ctx->i_ae);
+ break;
+ }
+ error(arg);
+ break;
+ case 'W':
+ if (strncmp(arg, "-Wp,-xc99", 9) == 0) {
+ /*
+ * gcc's preprocessor will accept c99
+ * regardless, so accept and ignore.
+ */
+ break;
+ }
+ if (strncmp(arg, "-Wa,", 4) == 0 ||
+ strncmp(arg, "-Wp,", 4) == 0 ||
+ strncmp(arg, "-Wl,", 4) == 0) {
+ newae(ctx->i_ae, arg);
+ break;
+ }
+ if (strcmp(arg, "-W0,-noglobal") == 0 ||
+ strcmp(arg, "-W0,-xglobalstatic") == 0) {
+ /*
+ * gcc doesn't prefix local symbols
+ * in debug mode, so this is not needed.
+ */
+ break;
+ }
+ if (strcmp(arg, "-W0,-Lt") == 0) {
+ /*
+ * Generate tests at the top of loops.
+ * There is no direct gcc equivalent, ignore.
+ */
+ break;
+ }
+ if (strcmp(arg, "-W0,-xdbggen=no%usedonly") == 0) {
+ newae(ctx->i_ae,
+ "-fno-eliminate-unused-debug-symbols");
+ newae(ctx->i_ae,
+ "-fno-eliminate-unused-debug-types");
+ break;
+ }
+ if (strcmp(arg, "-W2,-xwrap_int") == 0) {
+ /*
+ * Use the legacy behaviour (pre-SS11)
+ * for integer wrapping.
+ * gcc does not need this.
+ */
+ break;
+ }
+ if (strcmp(arg, "-Wd,-xsafe=unboundsym") == 0) {
+ /*
+ * Prevents optimizing away checks for
+ * unbound weak symbol addresses. gcc does
+ * not do this, so it's not needed.
+ */
+ break;
+ }
+ if (strncmp(arg, "-Wc,-xcode=", 11) == 0) {
+ xlate(ctx->i_ae, arg + 11, xcode_tbl);
+ break;
+ }
+ if (strncmp(arg, "-Wc,-Qiselect", 13) == 0) {
+ /*
+ * Prevents insertion of register symbols.
+ * gcc doesn't do this, so ignore it.
+ */
+ break;
+ }
+ if (strcmp(arg, "-Wc,-Qassembler-ounrefsym=0") == 0) {
+ /*
+ * Prevents optimizing away of static variables.
+ * gcc does not do this, so it's not needed.
+ */
+ break;
+ }
+#if defined(__x86)
+ if (strcmp(arg, "-Wu,-save_args") == 0) {
+ newae(ctx->i_ae, "-msave-args");
+ break;
+ }
+#endif /* __x86 */
+ error(arg);
+ break;
+ case 'X':
+ if (strcmp(arg, "-Xa") == 0 ||
+ strcmp(arg, "-Xt") == 0) {
+ break;
+ }
+ if (strcmp(arg, "-Xs") == 0) {
+ Xsmode(ctx->i_ae);
+ break;
+ }
+ error(arg);
+ break;
+ case 'x':
+ if (arglen == 1)
+ error(arg);
+ switch (arg[2]) {
+ case 'a':
+ if (strncmp(arg, "-xarch=", 7) == 0) {
+ mflag |= xlate_xtb(ctx->i_ae, arg + 7);
+ break;
+ }
+ error(arg);
+ break;
+ case 'b':
+ if (strncmp(arg, "-xbuiltin=", 10) == 0) {
+ if (strcmp(arg + 10, "%all"))
+ newae(ctx->i_ae, "-fbuiltin");
+ break;
+ }
+ error(arg);
+ break;
+ case 'C':
+ /* Accept C++ style comments -- ignore */
+ if (strcmp(arg, "-xCC") == 0)
+ break;
+ error(arg);
+ break;
+ case 'c':
+ if (strncmp(arg, "-xc99=%all", 10) == 0) {
+ newae(ctx->i_ae, "-std=gnu99");
+ break;
+ }
+ if (strncmp(arg, "-xc99=%none", 11) == 0) {
+ newae(ctx->i_ae, "-std=gnu89");
+ break;
+ }
+ if (strncmp(arg, "-xchip=", 7) == 0) {
+ xlate(ctx->i_ae, arg + 7, xchip_tbl);
+ break;
+ }
+ if (strncmp(arg, "-xcode=", 7) == 0) {
+ xlate(ctx->i_ae, arg + 7, xcode_tbl);
+ break;
+ }
+ if (strncmp(arg, "-xcrossfile", 11) == 0)
+ break;
+ error(arg);
+ break;
+ case 'd':
+ if (strncmp(arg, "-xdebugformat=", 14) == 0)
+ break;
+ error(arg);
+ break;
+ case 'F':
+ /*
+ * Compile for mapfile reordering, or unused
+ * section elimination, syntax can be -xF or
+ * more complex, like -xF=%all -- ignore.
+ */
+ if (strncmp(arg, "-xF", 3) == 0)
+ break;
+ error(arg);
+ break;
+ case 'i':
+ if (strncmp(arg, "-xinline", 8) == 0)
+ /* No inlining; ignore */
+ break;
+ if (strcmp(arg, "-xildon") == 0 ||
+ strcmp(arg, "-xildoff") == 0)
+ /* No incremental linking; ignore */
+ break;
+ error(arg);
+ break;
+#if defined(__x86)
+ case 'm':
+ if (strcmp(arg, "-xmodel=kernel") == 0) {
+ newae(ctx->i_ae, "-ffreestanding");
+ newae(ctx->i_ae, "-mno-red-zone");
+ model = "-mcmodel=kernel";
+ nolibc = 1;
+ break;
+ }
+ error(arg);
+ break;
+#endif /* __x86 */
+ case 'O':
+ if (strncmp(arg, "-xO", 3) == 0) {
+ size_t len = strlen(arg);
+ char *s = NULL;
+ int c = *(arg + 3);
+ int level;
+
+ if (len != 4 || !isdigit(c))
+ error(arg);
+
+ level = atoi(arg + 3);
+ if (level > 5)
+ error(arg);
+ if (level >= 2) {
+ /*
+ * For gcc-3.4.x at -O2 we
+ * need to disable optimizations
+ * that break ON.
+ */
+ optim_disable(ctx->i_ae, level);
+ /*
+ * limit -xO3 to -O2 as well.
+ */
+ level = 2;
+ }
+ if (asprintf(&s, "-O%d", level) == -1)
+ nomem();
+ newae(ctx->i_ae, s);
+ free(s);
+ break;
+ }
+ error(arg);
+ break;
+ case 'r':
+ if (strncmp(arg, "-xregs=", 7) == 0) {
+ xlate(ctx->i_ae, arg + 7, xregs_tbl);
+ break;
+ }
+ error(arg);
+ break;
+ case 's':
+ if (strcmp(arg, "-xs") == 0 ||
+ strcmp(arg, "-xspace") == 0 ||
+ strcmp(arg, "-xstrconst") == 0)
+ break;
+ error(arg);
+ break;
+ case 't':
+ if (strncmp(arg, "-xtarget=", 9) == 0) {
+ xlate(ctx->i_ae, arg + 9, xtarget_tbl);
+ break;
+ }
+ error(arg);
+ break;
+ case 'e':
+ case 'h':
+ case 'l':
+ default:
+ error(arg);
+ break;
+ }
+ break;
+ case 'Y':
+ if (arglen == 1) {
+ if ((arg = *++ctx->i_oldargv) == NULL ||
+ *arg == '\0')
+ error("-Y");
+ ctx->i_oldargc--;
+ arglen = strlen(arg + 1);
+ } else {
+ arg += 2;
+ }
+ /* Just ignore -YS,... for now */
+ if (strncmp(arg, "S,", 2) == 0)
+ break;
+ if (strncmp(arg, "l,", 2) == 0) {
+ char *s = strdup(arg);
+ s[0] = '-';
+ s[1] = 'B';
+ newae(ctx->i_ae, s);
+ free(s);
+ break;
+ }
+ if (strncmp(arg, "I,", 2) == 0) {
+ char *s = strdup(arg);
+ s[0] = '-';
+ s[1] = 'I';
+ newae(ctx->i_ae, "-nostdinc");
+ newae(ctx->i_ae, s);
+ free(s);
+ break;
+ }
+ error(arg);
+ break;
+ case 'Q':
+ /*
+ * We could map -Qy into -Wl,-Qy etc.
+ */
+ default:
+ error(arg);
+ break;
+ }
+ }
+
+ free(nameflag);
+
+ /*
+ * When compiling multiple source files in a single invocation some
+ * compilers output objects into the current directory with
+ * predictable and conventional names.
+ *
+ * We prevent any attempt to compile multiple files at once so that
+ * any such objects created by a shadow can't escape into a later
+ * link-edit.
+ */
+ if (c_files > 1 && op != CW_O_PREPROCESS) {
+ errx(2, "multiple source files are "
+ "allowed only with -E or -P");
+ }
+
+ /*
+ * Make sure that we do not have any unintended interactions between
+ * the xarch options passed in and the version of the Studio compiler
+ * used.
+ */
+ if ((mflag & (SS11|SS12)) == (SS11|SS12)) {
+ errx(2,
+ "Conflicting \"-xarch=\" flags (both Studio 11 and 12)\n");
+ }
+
+ switch (mflag) {
+ case 0:
+ /* FALLTHROUGH */
+ case M32:
+#if defined(__sparc)
+ /*
+ * Only -m32 is defined and so put in the missing xarch
+ * translation.
+ */
+ newae(ctx->i_ae, "-mcpu=v8");
+ newae(ctx->i_ae, "-mno-v8plus");
+#endif
+ break;
+ case M64:
+#if defined(__sparc)
+ /*
+ * Only -m64 is defined and so put in the missing xarch
+ * translation.
+ */
+ newae(ctx->i_ae, "-mcpu=v9");
+#endif
+ break;
+ case SS12:
+#if defined(__sparc)
+ /* no -m32/-m64 flag used - this is an error for sparc builds */
+ (void) fprintf(stderr, "No -m32/-m64 flag defined\n");
+ exit(2);
+#endif
+ break;
+ case SS11:
+ /* FALLTHROUGH */
+ case (SS11|M32):
+ case (SS11|M64):
+ break;
+ case (SS12|M32):
+#if defined(__sparc)
+ /*
+ * Need to add in further 32 bit options because with SS12
+ * the xarch=sparcvis option can be applied to 32 or 64
+ * bit, and so the translatation table (xtbl) cannot handle
+ * that.
+ */
+ newae(ctx->i_ae, "-mv8plus");
+#endif
+ break;
+ case (SS12|M64):
+ break;
+ default:
+ (void) fprintf(stderr,
+ "Incompatible -xarch= and/or -m32/-m64 options used.\n");
+ exit(2);
+ }
+
+ if (ctx->i_flags & CW_F_SHADOW) {
+ if (op == CW_O_PREPROCESS)
+ exit(0);
+ else if (op == CW_O_LINK && c_files == 0)
+ exit(0);
+ }
+
+ if (model != NULL)
+ newae(ctx->i_ae, model);
+ if (!nolibc)
+ newae(ctx->i_ae, "-lc");
+ if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
+ ctx->i_discard = discard_file_name(NULL);
+ newae(ctx->i_ae, "-o");
+ newae(ctx->i_ae, ctx->i_discard);
+ }
+}
+
+static void
+do_cc(cw_ictx_t *ctx)
+{
+ int in_output = 0, seen_o = 0, c_files = 0;
+ cw_op_t op = CW_O_LINK;
+ char *nameflag;
+
+ if (ctx->i_flags & CW_F_PROG) {
+ newae(ctx->i_ae, "-V");
+ return;
+ }
+
+ if (asprintf(&nameflag, "-_%s=", ctx->i_compiler->c_name) == -1)
+ nomem();
+
+ while (--ctx->i_oldargc > 0) {
+ char *arg = *++ctx->i_oldargv;
+ size_t arglen = strlen(arg);
+
+ if (strncmp(arg, "-_CC=", 5) == 0) {
+ newae(ctx->i_ae, strchr(arg, '=') + 1);
+ continue;
+ }
+
+ if (*arg != '-') {
+ if (!in_output && arglen > 2 &&
+ arg[arglen - 2] == '.' &&
+ (arg[arglen - 1] == 'S' || arg[arglen - 1] == 's' ||
+ arg[arglen - 1] == 'c' || arg[arglen - 1] == 'i'))
+ c_files++;
+
+ if (in_output == 0 || !(ctx->i_flags & CW_F_SHADOW)) {
+ newae(ctx->i_ae, arg);
+ } else {
+ in_output = 0;
+ ctx->i_discard = discard_file_name(arg);
+ newae(ctx->i_ae, ctx->i_discard);
+ }
+ continue;
+ }
+ switch (*(arg + 1)) {
+ case '_':
+ if ((strncmp(arg, nameflag, strlen(nameflag)) == 0) ||
+ (strncmp(arg, "-_cc=", 5) == 0) ||
+ (strncmp(arg, "-_sun=", 6) == 0)) {
+ newae(ctx->i_ae, strchr(arg, '=') + 1);
+ }
+ break;
+
+ case 'V':
+ ctx->i_flags &= ~CW_F_ECHO;
+ newae(ctx->i_ae, arg);
+ break;
+ case 'o':
+ seen_o = 1;
+ if (strlen(arg) == 2) {
+ in_output = 1;
+ newae(ctx->i_ae, arg);
+ } else if (ctx->i_flags & CW_F_SHADOW) {
+ newae(ctx->i_ae, "-o");
+ ctx->i_discard = discard_file_name(arg);
+ newae(ctx->i_ae, ctx->i_discard);
+ } else {
+ newae(ctx->i_ae, arg);
+ }
+ break;
+ case 'c':
+ case 'S':
+ if (strlen(arg) == 2)
+ op = CW_O_COMPILE;
+ newae(ctx->i_ae, arg);
+ break;
+ case 'E':
+ case 'P':
+ if (strlen(arg) == 2)
+ op = CW_O_PREPROCESS;
+ /*FALLTHROUGH*/
+ default:
+ newae(ctx->i_ae, arg);
+ }
+ }
+
+ free(nameflag);
+
+ /* See the comment on this same code in do_gcc() */
+ if (c_files > 1 && op != CW_O_PREPROCESS) {
+ errx(2, "multiple source files are "
+ "allowed only with -E or -P");
+ }
+
+ if (ctx->i_flags & CW_F_SHADOW) {
+ if (op == CW_O_PREPROCESS)
+ exit(0);
+ else if (op == CW_O_LINK && c_files == 0)
+ exit(0);
+ }
+
+ if (!seen_o && (ctx->i_flags & CW_F_SHADOW)) {
+ newae(ctx->i_ae, "-o");
+ ctx->i_discard = discard_file_name(NULL);
+ newae(ctx->i_ae, ctx->i_discard);
+ }
+}
+
+static void
+prepctx(cw_ictx_t *ctx)
+{
+ newae(ctx->i_ae, ctx->i_compiler->c_path);
+
+ if (ctx->i_flags & CW_F_PROG) {
+ (void) printf("%s: %s\n", (ctx->i_flags & CW_F_SHADOW) ?
+ "shadow" : "primary", ctx->i_compiler->c_path);
+ (void) fflush(stdout);
+ }
+
+ if (!(ctx->i_flags & CW_F_XLATE))
+ return;
+
+ switch (ctx->i_compiler->c_style) {
+ case SUN:
+ do_cc(ctx);
+ break;
+ case GNU:
+ do_gcc(ctx);
+ break;
+ }
+}
+
+static int
+invoke(cw_ictx_t *ctx)
+{
+ char **newargv;
+ int ac;
+ struct ae *a;
+
+ if ((newargv = calloc(sizeof (*newargv), ctx->i_ae->ael_argc + 1)) ==
+ NULL)
+ nomem();
+
+ if (ctx->i_flags & CW_F_ECHO)
+ (void) fprintf(stderr, "+ ");
+
+ for (ac = 0, a = ctx->i_ae->ael_head; a; a = a->ae_next, ac++) {
+ newargv[ac] = a->ae_arg;
+ if (ctx->i_flags & CW_F_ECHO)
+ (void) fprintf(stderr, "%s ", a->ae_arg);
+ if (a == ctx->i_ae->ael_tail)
+ break;
+ }
+
+ if (ctx->i_flags & CW_F_ECHO) {
+ (void) fprintf(stderr, "\n");
+ (void) fflush(stderr);
+ }
+
+ if (!(ctx->i_flags & CW_F_EXEC))
+ return (0);
+
+ /*
+ * We must fix up the environment here so that the dependency files are
+ * not trampled by the shadow compiler. Also take care of GCC
+ * environment variables that will throw off gcc. This assumes a primary
+ * gcc.
+ */
+ if ((ctx->i_flags & CW_F_SHADOW) &&
+ (unsetenv("SUNPRO_DEPENDENCIES") != 0 ||
+ unsetenv("DEPENDENCIES_OUTPUT") != 0 ||
+ unsetenv("GCC_ROOT") != 0)) {
+ (void) fprintf(stderr, "error: environment setup failed: %s\n",
+ strerror(errno));
+ return (-1);
+ }
+
+ (void) execv(newargv[0], newargv);
+ warn("couldn't run %s", newargv[0]);
+
+ return (-1);
+}
+
+static int
+reap(cw_ictx_t *ctx)
+{
+ int status, ret = 0;
+ char buf[1024];
+ struct stat s;
+
+ /*
+ * Only wait for one specific child.
+ */
+ if (ctx->i_pid <= 0)
+ return (-1);
+
+ do {
+ if (waitpid(ctx->i_pid, &status, 0) < 0) {
+ warn("cannot reap child");
+ return (-1);
+ }
+ if (status != 0) {
+ if (WIFSIGNALED(status)) {
+ ret = -WTERMSIG(status);
+ break;
+ } else if (WIFEXITED(status)) {
+ ret = WEXITSTATUS(status);
+ break;
+ }
+ }
+ } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+
+ (void) unlink(ctx->i_discard);
+ free(ctx->i_discard);
+
+ if (stat(ctx->i_stderr, &s) < 0) {
+ warn("stat failed on child cleanup");
+ return (-1);
+ }
+ if (s.st_size != 0) {
+ FILE *f;
+
+ if ((f = fopen(ctx->i_stderr, "r")) != NULL) {
+ while (fgets(buf, sizeof (buf), f))
+ (void) fprintf(stderr, "%s", buf);
+ (void) fflush(stderr);
+ (void) fclose(f);
+ }
+ }
+ (void) unlink(ctx->i_stderr);
+ free(ctx->i_stderr);
+
+ /*
+ * cc returns an error code when given -V; we want that to succeed.
+ */
+ if (ctx->i_flags & CW_F_PROG)
+ return (0);
+
+ return (ret);
+}
+
+static int
+exec_ctx(cw_ictx_t *ctx, int block)
+{
+ if ((ctx->i_stderr = tempnam(NULL, ".cw")) == NULL) {
+ nomem();
+ return (-1);
+ }
+
+ if ((ctx->i_pid = fork()) == 0) {
+ int fd;
+
+ (void) fclose(stderr);
+ if ((fd = open(ctx->i_stderr, O_WRONLY | O_CREAT | O_EXCL,
+ 0666)) < 0) {
+ err(1, "open failed for standard error");
+ }
+ if (dup2(fd, 2) < 0) {
+ err(1, "dup2 failed for standard error");
+ }
+ if (fd != 2)
+ (void) close(fd);
+ if (freopen("/dev/fd/2", "w", stderr) == NULL) {
+ err(1, "freopen failed for /dev/fd/2");
+ }
+
+ prepctx(ctx);
+ exit(invoke(ctx));
+ }
+
+ if (ctx->i_pid < 0) {
+ err(1, "fork failed");
+ }
+
+ if (block)
+ return (reap(ctx));
+
+ return (0);
+}
+
+static void
+parse_compiler(const char *spec, cw_compiler_t *compiler)
+{
+ char *tspec, *token;
+
+ if ((tspec = strdup(spec)) == NULL)
+ nomem();
+
+ if ((token = strsep(&tspec, ",")) == NULL)
+ errx(1, "Compiler is missing a name: %s", spec);
+ compiler->c_name = token;
+
+ if ((token = strsep(&tspec, ",")) == NULL)
+ errx(1, "Compiler is missing a path: %s", spec);
+ compiler->c_path = token;
+
+ if ((token = strsep(&tspec, ",")) == NULL)
+ errx(1, "Compiler is missing a style: %s", spec);
+
+ if ((strcasecmp(token, "gnu") == 0) ||
+ (strcasecmp(token, "gcc") == 0))
+ compiler->c_style = GNU;
+ else if ((strcasecmp(token, "sun") == 0) ||
+ (strcasecmp(token, "cc") == 0))
+ compiler->c_style = SUN;
+ else
+ errx(1, "unknown compiler style: %s", token);
+
+ if (tspec != NULL)
+ errx(1, "Excess tokens in compiler: %s", spec);
+}
+
+int
+main(int argc, char **argv)
+{
+ int ch;
+ cw_compiler_t primary = { NULL, NULL, 0 };
+ cw_compiler_t shadows[10];
+ int nshadows = 0;
+ int ret = 0;
+ boolean_t do_serial = B_FALSE;
+ boolean_t do_exec = B_FALSE;
+ boolean_t vflg = B_FALSE;
+ boolean_t Cflg = B_FALSE;
+ boolean_t cflg = B_FALSE;
+ boolean_t nflg = B_FALSE;
+
+ cw_ictx_t *main_ctx;
+
+ static struct option longopts[] = {
+ { "compiler", no_argument, NULL, 'c' },
+ { "noecho", no_argument, NULL, 'n' },
+ { "primary", required_argument, NULL, 'p' },
+ { "shadow", required_argument, NULL, 's' },
+ { "versions", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 },
+ };
+
+
+ if ((main_ctx = newictx()) == NULL)
+ nomem();
+
+ while ((ch = getopt_long(argc, argv, "C", longopts, NULL)) != -1) {
+ switch (ch) {
+ case 'c':
+ cflg = B_TRUE;
+ break;
+ case 'C':
+ Cflg = B_TRUE;
+ break;
+ case 'n':
+ nflg = B_TRUE;
+ break;
+ case 'p':
+ if (primary.c_path != NULL) {
+ warnx("Only one primary compiler may "
+ "be specified");
+ usage();
+ }
+
+ parse_compiler(optarg, &primary);
+ break;
+ case 's':
+ if (nshadows >= 10)
+ errx(1, "May only use 10 shadows at "
+ "the moment");
+ parse_compiler(optarg, &shadows[nshadows]);
+ nshadows++;
+ break;
+ case 'v':
+ vflg = B_TRUE;
+ break;
+ default:
+ (void) fprintf(stderr, "Did you forget '--'?\n");
+ usage();
+ }
+ }
+
+ if (primary.c_path == NULL) {
+ warnx("A primary compiler must be specified");
+ usage();
+ }
+
+ do_serial = (getenv("CW_SHADOW_SERIAL") == NULL) ? B_FALSE : B_TRUE;
+ do_exec = (getenv("CW_NO_EXEC") == NULL) ? B_TRUE : B_FALSE;
+
+ /* Leave room for argv[0] */
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ main_ctx->i_oldargc = argc;
+ main_ctx->i_oldargv = argv;
+ main_ctx->i_flags = CW_F_XLATE;
+ if (nflg == 0)
+ main_ctx->i_flags |= CW_F_ECHO;
+ if (do_exec)
+ main_ctx->i_flags |= CW_F_EXEC;
+ if (Cflg)
+ main_ctx->i_flags |= CW_F_CXX;
+ main_ctx->i_compiler = &primary;
+
+ if (cflg) {
+ (void) fputs(primary.c_path, stdout);
+ }
+
+ if (vflg) {
+ (void) printf("cw version %s\n", CW_VERSION);
+ (void) fflush(stdout);
+ main_ctx->i_flags &= ~CW_F_ECHO;
+ main_ctx->i_flags |= CW_F_PROG | CW_F_EXEC;
+ do_serial = 1;
+ }
+
+ ret |= exec_ctx(main_ctx, do_serial);
+
+ for (int i = 0; i < nshadows; i++) {
+ int r;
+ cw_ictx_t *shadow_ctx;
+
+ if ((shadow_ctx = newictx()) == NULL)
+ nomem();
+
+ memcpy(shadow_ctx, main_ctx, sizeof (cw_ictx_t));
+
+ shadow_ctx->i_flags |= CW_F_SHADOW;
+ shadow_ctx->i_compiler = &shadows[i];
+
+ r = exec_ctx(shadow_ctx, do_serial);
+ if (r == 0) {
+ shadow_ctx->i_next = main_ctx->i_next;
+ main_ctx->i_next = shadow_ctx;
+ }
+ ret |= r;
+ }
+
+ if (!do_serial) {
+ cw_ictx_t *next = main_ctx;
+ while (next != NULL) {
+ cw_ictx_t *toreap = next;
+ next = next->i_next;
+ ret |= reap(toreap);
+ }
+ }
+
+ return (ret);
+}