diff mbox series

[RFC] Fix plugin build errors on systems where unistd.h includes getopt.h

Message ID 20200616100901.414231-1-iii@linux.ibm.com
State New
Headers show
Series [RFC] Fix plugin build errors on systems where unistd.h includes getopt.h | expand

Commit Message

Ilya Leoshkevich June 16, 2020, 10:09 a.m. UTC
Hello,

I ran into an issue with building plugins, which appears to be fairly
old [1].  Below is my attempt to fix it - I'm currently verifying it on
various farm machines, and so far it's looking good.  I'm not sure
whether I went in the right direction with the fix though (portability
is hard!), so it would be great if someone knowledgeable could have a
look.

Best regards,
Ilya

[1] https://gcc.gnu.org/legacy-ml/gcc/2010-08/msg00106.html

---

On certain systems gcc plugin builds fail with

    install/lib/gcc/powerpc64le-unknown-linux-gnu/11.0.0/plugin/include/system.h:476:53: error: declaration of ‘int getopt(int, char* const*, const char*)’ has a different exception specifier
     extern int getopt (int, char * const *, const char *);
                                                     ^
    In file included from /usr/include/unistd.h:893:0,
                     from install/lib/gcc/powerpc64le-unknown-linux-gnu/11.0.0/plugin/include/system.h:294,
                     from install/lib/gcc/powerpc64le-unknown-linux-gnu/11.0.0/plugin/include/gcc-plugin.h:28,
                     from plugin.cpp:3:
    /usr/include/getopt.h:151:12: error: from previous declaration ‘int getopt(int, char* const*, const char*) throw ()’
     extern int getopt (int ___argc, char *const *___argv, const char *__shortopts)

errors.  The problem occurs on e.g. CentOS 7, but not on e.g. Fedora 31.
The difference is that unistd.h includes getopt.h on the former and
bits/getopt_posix.h on the latter.

gcc includes its own version of getopt.h, which is autoconf-aware: it
does not declare getopt if HAVE_DECL_GETOPT=1.  The important things
about it are that it is not installed and that it shadows platform's
getopt.h.

system.h, which is used during autoconf tests, includes unistd.h and
also declares getopt (unless HAVE_DECL_GETOPT=1).   When doing the
getopt presence test, autoconf defines HAVE_DECL_GETOPT=1 and includes
system.h.  On systems where unistd.h does not include getopt.h, no
shadowing happens, system.h ends up providing getopt, and autoconf
correctly concludes that HAVE_DECL_GETOPT=1.  On systems where unistd.h
does include getopt.h, shadowing happens, system.h ends up not
providing getopt, and autoconf incorrectly concludes that
HAVE_DECL_GETOPT=0.

When a plugin includes installed system.h, it gets two conflicting
definitions of getopt: one from platform's unistd.h, and one from
system.h itself - the latter arises because the installed auto-host.h
contains the incorrect #define HAVE_DECL_GETOPT 0.

The root cause is header shadowing causing the incorrect autoconf
decision, so fix this by removing getopt.h and moving the necessary
bits into the new gcc-getopt.h.

---
 gcc/Makefile.in         |   3 +-
 gcc/config.in           |  54 +++++++++++++++
 gcc/configure           |  54 +++++++++++++--
 gcc/configure.ac        |  16 ++++-
 gcc/gcov-dump.c         |   2 +-
 gcc/gcov-tool.c         |   2 +-
 gcc/gcov.c              |   2 +-
 gcc/gengtype.c          |   2 +-
 gcc/system.h            |   6 +-
 gcc/tsystem.h           |  11 ---
 include/gcc-getopt.h    |  79 +++++++++++++++++++++
 include/getopt.h        | 143 --------------------------------------
 libiberty/Makefile.in   |   6 +-
 libiberty/config.in     |  30 ++++++++
 libiberty/configure     | 147 ++++++++++++++++++++++++++++++++++++----
 libiberty/configure.ac  |  24 ++++++-
 libiberty/cp-demangle.c |   2 +-
 libiberty/getopt.c      |   2 +-
 libiberty/getopt1.c     |   2 +-
 19 files changed, 395 insertions(+), 192 deletions(-)
 create mode 100644 include/gcc-getopt.h
 delete mode 100644 include/getopt.h
diff mbox series

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 4f70c189b9d..37534247539 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -979,7 +979,8 @@  C_COMMON_H = c-family/c-common.h c-family/c-common.def $(TREE_H) \
 C_PRAGMA_H = c-family/c-pragma.h $(CPPLIB_H)
 C_TREE_H = c/c-tree.h $(C_COMMON_H) $(DIAGNOSTIC_H)
 SYSTEM_H = system.h hwint.h $(srcdir)/../include/libiberty.h \
-	$(srcdir)/../include/safe-ctype.h $(srcdir)/../include/filenames.h
+	$(srcdir)/../include/safe-ctype.h $(srcdir)/../include/filenames.h \
+	$(srcdir)/../include/gcc-getopt.h
 PREDICT_H = predict.h predict.def
 CPPLIB_H = $(srcdir)/../libcpp/include/line-map.h \
 	$(srcdir)/../libcpp/include/cpplib.h
diff --git a/gcc/config.in b/gcc/config.in
index 364eba47737..e835d5b842f 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -947,6 +947,13 @@ 
 #endif
 
 
+/* Define to 1 if we found a declaration for 'getopt_long', otherwise define
+   to 0. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_DECL_GETOPT_LONG
+#endif
+
+
 /* Define to 1 if we found a declaration for 'getpagesize', otherwise define
    to 0. */
 #ifndef USED_FOR_TARGET
@@ -1003,6 +1010,27 @@ 
 #endif
 
 
+/* Define to 1 if we found a declaration for 'no_argument', otherwise define
+   to 0. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_DECL_NO_ARGUMENT
+#endif
+
+
+/* Define to 1 if we found a declaration for 'optarg', otherwise define to 0.
+   */
+#ifndef USED_FOR_TARGET
+#undef HAVE_DECL_OPTARG
+#endif
+
+
+/* Define to 1 if we found a declaration for 'optind', otherwise define to 0.
+   */
+#ifndef USED_FOR_TARGET
+#undef HAVE_DECL_OPTIND
+#endif
+
+
 /* Define to 1 if we found a declaration for 'putchar_unlocked', otherwise
    define to 0. */
 #ifndef USED_FOR_TARGET
@@ -1024,6 +1052,13 @@ 
 #endif
 
 
+/* Define to 1 if we found a declaration for 'required_argument', otherwise
+   define to 0. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_DECL_REQUIRED_ARGUMENT
+#endif
+
+
 /* Define to 1 if we found a declaration for 'sbrk', otherwise define to 0. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_DECL_SBRK
@@ -1149,6 +1184,13 @@ 
 #endif
 
 
+/* Define to 1 if we found a declaration for '_getopt_internal', otherwise
+   define to 0. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_DECL__GETOPT_INTERNAL
+#endif
+
+
 /* Define to 1 if you have the <direct.h> header file. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_DIRECT_H
@@ -1376,6 +1418,12 @@ 
 #endif
 
 
+/* Define to 1 if you have the <getopt.h> header file. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_GETOPT_H
+#endif
+
+
 /* Define to 1 if you have the `getrlimit' function. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_GETRLIMIT
@@ -1804,6 +1852,12 @@ 
 #endif
 
 
+/* Set to 1 if struct option is defined, otherwise to 0. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_STRUCT_OPTION
+#endif
+
+
 /* Define if <sys/times.h> defines struct tms. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_STRUCT_TMS
diff --git a/gcc/configure b/gcc/configure
index f224679ed3e..8ce6373773f 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -785,10 +785,10 @@  manext
 LIBICONV_DEP
 LTLIBICONV
 LIBICONV
-ZSTD_LIB
-ZSTD_INCLUDE
 ZSTD_LDFLAGS
 ZSTD_CPPFLAGS
+ZSTD_LIB
+ZSTD_INCLUDE
 DL_LIB
 LDEXP_LIB
 EXTRA_GCC_LIBS
@@ -9006,7 +9006,8 @@  fi
 for ac_header in limits.h stddef.h string.h strings.h stdlib.h time.h iconv.h \
 		 fcntl.h ftw.h unistd.h sys/file.h sys/time.h sys/mman.h \
 		 sys/resource.h sys/param.h sys/times.h sys/stat.h \
-		 direct.h malloc.h langinfo.h ldfcn.h locale.h wchar.h
+		 direct.h malloc.h langinfo.h ldfcn.h locale.h wchar.h \
+		 getopt.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_cxx_check_header_preproc "$LINENO" "$ac_header" "$as_ac_Header"
@@ -9978,6 +9979,8 @@  ZSTD_LIB=
 ZSTD_CPPFLAGS=
 ZSTD_LDFLAGS=
 
+
+
 # Check whether --with-zstd was given.
 if test "${with_zstd+set}" = set; then :
   withval=$with_zstd;
@@ -11451,7 +11454,8 @@  for ac_func in getenv atol atoll asprintf sbrk abort atof getcwd getwd \
 	madvise stpcpy strnlen strsignal strverscmp \
 	strtol strtoul strtoll strtoull setenv unsetenv \
 	errno snprintf vsnprintf vasprintf malloc realloc calloc \
-	free getopt clock getpagesize ffs clearerr_unlocked feof_unlocked   ferror_unlocked fflush_unlocked fgetc_unlocked fgets_unlocked   fileno_unlocked fprintf_unlocked fputc_unlocked fputs_unlocked   fread_unlocked fwrite_unlocked getchar_unlocked getc_unlocked   putchar_unlocked putc_unlocked
+	free optarg optind getopt no_argument required_argument getopt_long \
+	_getopt_internal clock getpagesize ffs clearerr_unlocked feof_unlocked   ferror_unlocked fflush_unlocked fgetc_unlocked fgets_unlocked   fileno_unlocked fprintf_unlocked fputc_unlocked fputs_unlocked   fread_unlocked fwrite_unlocked getchar_unlocked getc_unlocked   putchar_unlocked putc_unlocked
 do
   ac_tr_decl=`$as_echo "HAVE_DECL_$ac_func" | $as_tr_cpp`
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $ac_func is declared" >&5
@@ -11923,6 +11927,42 @@  $as_echo "#define HOST_HAS_F_SETLKW 1" >>confdefs.h
 
 fi
 
+# Check if struct option is defined.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct option" >&5
+$as_echo_n "checking for struct option... " >&6; }
+if ${ac_cv_struct_option+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define HAVE_STRUCT_OPTION 1
+#include "ansidecl.h"
+#include "system.h"
+int
+main ()
+{
+struct option option;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_struct_option=1
+else
+  ac_cv_struct_option=0
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_option" >&5
+$as_echo "$ac_cv_struct_option" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_OPTION $ac_cv_struct_option
+_ACEOF
+
+
 # Restore CFLAGS, CXXFLAGS from before the gcc_AC_NEED_DECLARATIONS tests.
 CFLAGS="$saved_CFLAGS"
 CXXFLAGS="$saved_CXXFLAGS"
@@ -19021,7 +19061,7 @@  else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 19022 "configure"
+#line 19064 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -19127,7 +19167,7 @@  else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 19128 "configure"
+#line 19170 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -31587,7 +31627,7 @@  config.status
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C)  Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index e83f0833ef3..6e9f36a337d 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -1215,7 +1215,8 @@  AC_HEADER_TIOCGWINSZ
 AC_CHECK_HEADERS(limits.h stddef.h string.h strings.h stdlib.h time.h iconv.h \
 		 fcntl.h ftw.h unistd.h sys/file.h sys/time.h sys/mman.h \
 		 sys/resource.h sys/param.h sys/times.h sys/stat.h \
-		 direct.h malloc.h langinfo.h ldfcn.h locale.h wchar.h)
+		 direct.h malloc.h langinfo.h ldfcn.h locale.h wchar.h \
+		 getopt.h)
 
 # Check for thread headers.
 AC_CHECK_HEADER(thread.h, [have_thread_h=yes], [have_thread_h=])
@@ -1485,7 +1486,8 @@  gcc_AC_CHECK_DECLS(getenv atol atoll asprintf sbrk abort atof getcwd getwd \
 	madvise stpcpy strnlen strsignal strverscmp \
 	strtol strtoul strtoll strtoull setenv unsetenv \
 	errno snprintf vsnprintf vasprintf malloc realloc calloc \
-	free getopt clock getpagesize ffs gcc_UNLOCKED_FUNCS, , ,[
+	free optarg optind getopt no_argument required_argument getopt_long \
+	_getopt_internal clock getpagesize ffs gcc_UNLOCKED_FUNCS, , ,[
 #include "ansidecl.h"
 #include "system.h"])
 
@@ -1584,6 +1586,16 @@  if test $ac_cv_f_setlkw = yes; then
   [Define if F_SETLKW supported by fcntl.])
 fi
 
+# Check if struct option is defined.
+AC_CACHE_CHECK(for struct option, ac_cv_struct_option, [
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#define HAVE_STRUCT_OPTION 1
+#include "ansidecl.h"
+#include "system.h"]], [[struct option option;]])],
+[ac_cv_struct_option=1],[ac_cv_struct_option=0])])
+AC_DEFINE_UNQUOTED([HAVE_STRUCT_OPTION], [$ac_cv_struct_option],
+[Set to 1 if struct option is defined, otherwise to 0.])
+
 # Restore CFLAGS, CXXFLAGS from before the gcc_AC_NEED_DECLARATIONS tests.
 CFLAGS="$saved_CFLAGS"
 CXXFLAGS="$saved_CXXFLAGS"
diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c
index ffb71ca4b68..01ce7eaedd3 100644
--- a/gcc/gcov-dump.c
+++ b/gcc/gcov-dump.c
@@ -23,7 +23,7 @@  along with Gcov; see the file COPYING3.  If not see
 #include "version.h"
 #include "intl.h"
 #include "diagnostic.h"
-#include <getopt.h>
+#include <gcc-getopt.h>
 #define IN_GCOV (-1)
 #include "gcov-io.h"
 #include "gcov-io.c"
diff --git a/gcc/gcov-tool.c b/gcc/gcov-tool.c
index f8f1cb5d29b..bc476bc1742 100644
--- a/gcc/gcov-tool.c
+++ b/gcc/gcov-tool.c
@@ -38,7 +38,7 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #if HAVE_FTW_H
 #include <ftw.h>
 #endif
-#include <getopt.h>
+#include <gcc-getopt.h>
 
 extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int);
 extern int gcov_profile_overlap (struct gcov_info*, struct gcov_info*);
diff --git a/gcc/gcov.c b/gcc/gcov.c
index 488847231c2..42715cb3cdc 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -48,7 +48,7 @@  along with Gcov; see the file COPYING3.  If not see
 #include "json.h"
 
 #include <zlib.h>
-#include <getopt.h>
+#include <gcc-getopt.h>
 
 #include "md5.h"
 
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 981577481af..5b91aa8902f 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -25,7 +25,7 @@ 
 #endif
 #include "system.h"
 #include "errors.h"		/* for fatal */
-#include "getopt.h"
+#include "gcc-getopt.h"
 #include "version.h"		/* for version_string & pkgversion_string.  */
 #include "xregex.h"
 #include "obstack.h"
diff --git a/gcc/system.h b/gcc/system.h
index 544f7ba427f..40f58d0d612 100644
--- a/gcc/system.h
+++ b/gcc/system.h
@@ -460,6 +460,8 @@  extern double atof (const char *);
 extern long atol (const char *);
 #endif
 
+#include "gcc-getopt.h"
+
 #if defined (HAVE_DECL_FREE) && !HAVE_DECL_FREE
 extern void free (void *);
 #endif
@@ -472,10 +474,6 @@  extern char *getcwd (char *, size_t);
 extern char *getenv (const char *);
 #endif
 
-#if defined (HAVE_DECL_GETOPT) && !HAVE_DECL_GETOPT
-extern int getopt (int, char * const *, const char *);
-#endif
-
 #if defined (HAVE_DECL_GETPAGESIZE) && !HAVE_DECL_GETPAGESIZE
 extern int getpagesize (void);
 #endif
diff --git a/gcc/tsystem.h b/gcc/tsystem.h
index 7be25131364..ac1d85c2321 100644
--- a/gcc/tsystem.h
+++ b/gcc/tsystem.h
@@ -26,17 +26,6 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #ifndef GCC_TSYSTEM_H
 #define GCC_TSYSTEM_H
 
-/* System headers (e.g. stdio.h, stdlib.h, unistd.h) sometimes
-   indirectly include getopt.h.  Our -I flags will cause gcc's gnu
-   getopt.h to be included, not the platform's copy.  In the default
-   case, gnu getopt.h will provide us with a no-argument prototype
-   which will generate -Wstrict-prototypes warnings.  None of the
-   target files actually use getopt, so it is safe to tell gnu
-   getopt.h we never need this prototype.  */
-#ifndef HAVE_DECL_GETOPT
-#define HAVE_DECL_GETOPT 1
-#endif
-
 /* We want everything from the glibc headers.  */
 #define _GNU_SOURCE 1
 
diff --git a/include/gcc-getopt.h b/include/gcc-getopt.h
new file mode 100644
index 00000000000..0b528fd334c
--- /dev/null
+++ b/include/gcc-getopt.h
@@ -0,0 +1,79 @@ 
+/* getopt declarations based on autoconf macros.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_GETOPT_H
+#define GCC_GETOPT_H
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#if defined(HAVE_DECL_OPTARG) && !HAVE_DECL_OPTARG
+extern char *optarg;
+#endif
+
+#if defined(HAVE_DECL_OPTIND) && !HAVE_DECL_OPTIND
+extern int optind;
+#endif
+
+#if defined(HAVE_STRUCT_OPTION) && !HAVE_STRUCT_OPTION
+struct option
+{
+#if defined(__STDC__) && __STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+#endif
+
+#if defined(HAVE_DECL_NO_ARGUMENT) && !HAVE_DECL_NO_ARGUMENT
+#define no_argument 0
+#endif
+
+#if defined(HAVE_DECL_REQUIRED_ARGUMENT) && !HAVE_DECL_REQUIRED_ARGUMENT
+#define required_argument 1
+#endif
+
+#if defined(HAVE_DECL_GETOPT) && !HAVE_DECL_GETOPT
+extern int getopt (int, char *const *, const char *);
+#endif
+
+#if defined(HAVE_DECL_GETOPT_LONG) && !HAVE_DECL_GETOPT_LONG
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+			const struct option *longopts, int *longind);
+#endif
+
+#if defined(HAVE_DECL__GETOPT_INTERNAL) && !HAVE_DECL__GETOPT_INTERNAL
+extern int _getopt_internal (int argc, char *const *argv,
+			     const char *shortopts,
+			     const struct option *longopts, int *longind,
+			     int long_only);
+#endif
+
+#endif
diff --git a/include/getopt.h b/include/getopt.h
deleted file mode 100644
index eca40f43a97..00000000000
--- a/include/getopt.h
+++ /dev/null
@@ -1,143 +0,0 @@ 
-/* Declarations for getopt.
-   Copyright (C) 1989-2020 Free Software Foundation, Inc.
-
-   NOTE: The canonical source of this file is maintained with the GNU C Library.
-   Bugs can be reported to bug-glibc@gnu.org.
-
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 2, or (at your option) any
-   later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
-   USA.  */
-
-#ifndef _GETOPT_H
-#define _GETOPT_H 1
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-/* For communication from `getopt' to the caller.
-   When `getopt' finds an option that takes an argument,
-   the argument value is returned here.
-   Also, when `ordering' is RETURN_IN_ORDER,
-   each non-option ARGV-element is returned here.  */
-
-extern char *optarg;
-
-/* Index in ARGV of the next element to be scanned.
-   This is used for communication to and from the caller
-   and for communication between successive calls to `getopt'.
-
-   On entry to `getopt', zero means this is the first call; initialize.
-
-   When `getopt' returns -1, this is the index of the first of the
-   non-option elements that the caller should itself scan.
-
-   Otherwise, `optind' communicates from one call to the next
-   how much of ARGV has been scanned so far.  */
-
-extern int optind;
-
-/* Callers store zero here to inhibit the error message `getopt' prints
-   for unrecognized options.  */
-
-extern int opterr;
-
-/* Set to an option character which was unrecognized.  */
-
-extern int optopt;
-
-/* Describe the long-named options requested by the application.
-   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
-   of `struct option' terminated by an element containing a name which is
-   zero.
-
-   The field `has_arg' is:
-   no_argument		(or 0) if the option does not take an argument,
-   required_argument	(or 1) if the option requires an argument,
-   optional_argument 	(or 2) if the option takes an optional argument.
-
-   If the field `flag' is not NULL, it points to a variable that is set
-   to the value given in the field `val' when the option is found, but
-   left unchanged if the option is not found.
-
-   To have a long-named option do something other than set an `int' to
-   a compiled-in constant, such as set a value from `optarg', set the
-   option's `flag' field to zero and its `val' field to a nonzero
-   value (the equivalent single-letter option character, if there is
-   one).  For long options that have a zero `flag' field, `getopt'
-   returns the contents of the `val' field.  */
-
-struct option
-{
-#if defined (__STDC__) && __STDC__
-  const char *name;
-#else
-  char *name;
-#endif
-  /* has_arg can't be an enum because some compilers complain about
-     type mismatches in all the code that assumes it is an int.  */
-  int has_arg;
-  int *flag;
-  int val;
-};
-
-/* Names for the values of the `has_arg' field of `struct option'.  */
-
-#define	no_argument		0
-#define required_argument	1
-#define optional_argument	2
-
-#if defined (__STDC__) && __STDC__
-/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1.  If it is
-   undefined, we haven't run the autoconf check so provide the
-   declaration without arguments.  If it is 0, we checked and failed
-   to find the declaration so provide a fully prototyped one.  If it
-   is 1, we found it so don't provide any declaration at all.  */
-#if !HAVE_DECL_GETOPT
-#if defined (__GNU_LIBRARY__) || defined (HAVE_DECL_GETOPT)
-/* Many other libraries have conflicting prototypes for getopt, with
-   differences in the consts, in unistd.h.  To avoid compilation
-   errors, only prototype getopt for the GNU C library.  */
-extern int getopt (int argc, char *const *argv, const char *shortopts);
-#else
-#ifndef __cplusplus
-extern int getopt ();
-#endif /* __cplusplus */
-#endif
-#endif /* !HAVE_DECL_GETOPT */
-
-extern int getopt_long (int argc, char *const *argv, const char *shortopts,
-		        const struct option *longopts, int *longind);
-extern int getopt_long_only (int argc, char *const *argv,
-			     const char *shortopts,
-		             const struct option *longopts, int *longind);
-
-/* Internal only.  Users should not call this directly.  */
-extern int _getopt_internal (int argc, char *const *argv,
-			     const char *shortopts,
-		             const struct option *longopts, int *longind,
-			     int long_only);
-#else /* not __STDC__ */
-extern int getopt ();
-extern int getopt_long ();
-extern int getopt_long_only ();
-
-extern int _getopt_internal ();
-#endif /* __STDC__ */
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif /* getopt.h */
diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in
index d6b302e02fd..ea2ae177e1e 100644
--- a/libiberty/Makefile.in
+++ b/libiberty/Makefile.in
@@ -659,7 +659,7 @@  $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir
 
 ./cp-demangle.$(objext): $(srcdir)/cp-demangle.c config.h $(INCDIR)/ansidecl.h \
 	$(srcdir)/cp-demangle.h $(INCDIR)/demangle.h \
-	$(INCDIR)/dyn-string.h $(INCDIR)/getopt.h $(INCDIR)/libiberty.h
+	$(INCDIR)/dyn-string.h $(INCDIR)/gcc-getopt.h $(INCDIR)/libiberty.h
 	if [ x"$(PICFLAG)" != x ]; then \
 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/cp-demangle.c -o pic/$@; \
 	else true; fi
@@ -822,7 +822,7 @@  $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir
 	$(COMPILE.c) $(srcdir)/getcwd.c $(OUTPUT_OPTION)
 
 ./getopt.$(objext): $(srcdir)/getopt.c config.h $(INCDIR)/ansidecl.h \
-	$(INCDIR)/getopt.h
+	$(INCDIR)/gcc-getopt.h
 	if [ x"$(PICFLAG)" != x ]; then \
 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/getopt.c -o pic/$@; \
 	else true; fi
@@ -831,7 +831,7 @@  $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir
 	else true; fi
 	$(COMPILE.c) $(srcdir)/getopt.c $(OUTPUT_OPTION)
 
-./getopt1.$(objext): $(srcdir)/getopt1.c config.h $(INCDIR)/getopt.h
+./getopt1.$(objext): $(srcdir)/getopt1.c config.h $(INCDIR)/gcc-getopt.h
 	if [ x"$(PICFLAG)" != x ]; then \
 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/getopt1.c -o pic/$@; \
 	else true; fi
diff --git a/libiberty/config.in b/libiberty/config.in
index f7052b5d958..ec8982183cb 100644
--- a/libiberty/config.in
+++ b/libiberty/config.in
@@ -63,14 +63,34 @@ 
    */
 #undef HAVE_DECL_GETOPT
 
+/* Define to 1 if you have the declaration of `getopt_long', and to 0 if you
+   don't. */
+#undef HAVE_DECL_GETOPT_LONG
+
 /* Define to 1 if you have the declaration of `malloc', and to 0 if you don't.
    */
 #undef HAVE_DECL_MALLOC
 
+/* Define to 1 if you have the declaration of `no_argument', and to 0 if you
+   don't. */
+#undef HAVE_DECL_NO_ARGUMENT
+
+/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't.
+   */
+#undef HAVE_DECL_OPTARG
+
+/* Define to 1 if you have the declaration of `optind', and to 0 if you don't.
+   */
+#undef HAVE_DECL_OPTIND
+
 /* Define to 1 if you have the declaration of `realloc', and to 0 if you
    don't. */
 #undef HAVE_DECL_REALLOC
 
+/* Define to 1 if you have the declaration of `required_argument', and to 0 if
+   you don't. */
+#undef HAVE_DECL_REQUIRED_ARGUMENT
+
 /* Define to 1 if you have the declaration of `sbrk', and to 0 if you don't.
    */
 #undef HAVE_DECL_SBRK
@@ -111,6 +131,10 @@ 
    don't. */
 #undef HAVE_DECL_VSNPRINTF
 
+/* Define to 1 if you have the declaration of `_getopt_internal', and to 0 if
+   you don't. */
+#undef HAVE_DECL__GETOPT_INTERNAL
+
 /* Define to 1 if you have the `dup3' function. */
 #undef HAVE_DUP3
 
@@ -126,6 +150,9 @@ 
 /* Define to 1 if you have the `getcwd' function. */
 #undef HAVE_GETCWD
 
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
 /* Define to 1 if you have the `getpagesize' function. */
 #undef HAVE_GETPAGESIZE
 
@@ -315,6 +342,9 @@ 
 /* Define to 1 if you have the `strtoull' function. */
 #undef HAVE_STRTOULL
 
+/* Set to 1 if struct option is defined, otherwise to 0. */
+#undef HAVE_STRUCT_OPTION
+
 /* Define to 1 if you have the `strverscmp' function. */
 #undef HAVE_STRVERSCMP
 
diff --git a/libiberty/configure b/libiberty/configure
index 1f8e23f0d23..9bf394fa4ad 100755
--- a/libiberty/configure
+++ b/libiberty/configure
@@ -5467,7 +5467,7 @@  host_makefile_frag=${frag}
 # It's OK to check for header files.  Although the compiler may not be
 # able to link anything, it had better be able to at least compile
 # something.
-for ac_header in sys/file.h sys/param.h limits.h stdlib.h malloc.h string.h unistd.h strings.h sys/time.h time.h sys/resource.h sys/stat.h sys/mman.h fcntl.h alloca.h sys/pstat.h sys/sysmp.h sys/sysinfo.h machine/hal_sysinfo.h sys/table.h sys/sysctl.h sys/systemcfg.h stdint.h stdio_ext.h process.h sys/prctl.h
+for ac_header in sys/file.h sys/param.h limits.h stdlib.h malloc.h string.h unistd.h strings.h sys/time.h time.h sys/resource.h sys/stat.h sys/mman.h fcntl.h alloca.h sys/pstat.h sys/sysmp.h sys/sysinfo.h machine/hal_sysinfo.h sys/table.h sys/sysctl.h sys/systemcfg.h stdint.h stdio_ext.h process.h sys/prctl.h getopt.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_preproc "$LINENO" "$ac_header" "$as_ac_Header"
@@ -7162,16 +7162,6 @@  fi
 cat >>confdefs.h <<_ACEOF
 #define HAVE_DECL_GETENV $ac_have_decl
 _ACEOF
-ac_fn_c_check_decl "$LINENO" "getopt" "ac_cv_have_decl_getopt" "$ac_includes_default"
-if test "x$ac_cv_have_decl_getopt" = xyes; then :
-  ac_have_decl=1
-else
-  ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_GETOPT $ac_have_decl
-_ACEOF
 ac_fn_c_check_decl "$LINENO" "malloc" "ac_cv_have_decl_malloc" "$ac_includes_default"
 if test "x$ac_cv_have_decl_malloc" = xyes; then :
   ac_have_decl=1
@@ -7313,6 +7303,139 @@  $as_echo "#define NEED_DECLARATION_CANONICALIZE_FILE_NAME 1" >>confdefs.h
 
 fi
 
+
+  saved_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -I${srcdir}/../include"
+  saved_CXXFLAGS="$CXXFLAGS"
+  CXXFLAGS="$CXXFLAGS -I${srcdir}/../include"
+  ac_fn_c_check_decl "$LINENO" "optarg" "ac_cv_have_decl_optarg" "
+#include \"ansidecl.h\"
+#include \"gcc-getopt.h\"
+"
+if test "x$ac_cv_have_decl_optarg" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_OPTARG $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "optind" "ac_cv_have_decl_optind" "
+#include \"ansidecl.h\"
+#include \"gcc-getopt.h\"
+"
+if test "x$ac_cv_have_decl_optind" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_OPTIND $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "getopt" "ac_cv_have_decl_getopt" "
+#include \"ansidecl.h\"
+#include \"gcc-getopt.h\"
+"
+if test "x$ac_cv_have_decl_getopt" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETOPT $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "no_argument" "ac_cv_have_decl_no_argument" "
+#include \"ansidecl.h\"
+#include \"gcc-getopt.h\"
+"
+if test "x$ac_cv_have_decl_no_argument" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_NO_ARGUMENT $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "required_argument" "ac_cv_have_decl_required_argument" "
+#include \"ansidecl.h\"
+#include \"gcc-getopt.h\"
+"
+if test "x$ac_cv_have_decl_required_argument" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_REQUIRED_ARGUMENT $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "getopt_long" "ac_cv_have_decl_getopt_long" "
+#include \"ansidecl.h\"
+#include \"gcc-getopt.h\"
+"
+if test "x$ac_cv_have_decl_getopt_long" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETOPT_LONG $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "_getopt_internal" "ac_cv_have_decl__getopt_internal" "
+#include \"ansidecl.h\"
+#include \"gcc-getopt.h\"
+"
+if test "x$ac_cv_have_decl__getopt_internal" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__GETOPT_INTERNAL $ac_have_decl
+_ACEOF
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct option" >&5
+$as_echo_n "checking for struct option... " >&6; }
+if ${ac_cv_struct_option+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define HAVE_STRUCT_OPTION 1
+#include "ansidecl.h"
+#include "gcc-getopt.h"
+int
+main ()
+{
+struct option option;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_struct_option=1
+else
+  ac_cv_struct_option=0
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_option" >&5
+$as_echo "$ac_cv_struct_option" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_OPTION $ac_cv_struct_option
+_ACEOF
+
+  CFLAGS="$saved_CFLAGS"
+  CXXFLAGS="$saved_CXXFLAGS"
 fi
 
 # Figure out which version of pexecute to use.
@@ -8231,7 +8354,7 @@  config.status
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C)  Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
diff --git a/libiberty/configure.ac b/libiberty/configure.ac
index 4e2599c14a8..0b2898d161f 100644
--- a/libiberty/configure.ac
+++ b/libiberty/configure.ac
@@ -270,7 +270,7 @@  AC_SUBST_FILE(host_makefile_frag)
 # It's OK to check for header files.  Although the compiler may not be
 # able to link anything, it had better be able to at least compile
 # something.
-AC_CHECK_HEADERS(sys/file.h sys/param.h limits.h stdlib.h malloc.h string.h unistd.h strings.h sys/time.h time.h sys/resource.h sys/stat.h sys/mman.h fcntl.h alloca.h sys/pstat.h sys/sysmp.h sys/sysinfo.h machine/hal_sysinfo.h sys/table.h sys/sysctl.h sys/systemcfg.h stdint.h stdio_ext.h process.h sys/prctl.h)
+AC_CHECK_HEADERS(sys/file.h sys/param.h limits.h stdlib.h malloc.h string.h unistd.h strings.h sys/time.h time.h sys/resource.h sys/stat.h sys/mman.h fcntl.h alloca.h sys/pstat.h sys/sysmp.h sys/sysinfo.h machine/hal_sysinfo.h sys/table.h sys/sysctl.h sys/systemcfg.h stdint.h stdio_ext.h process.h sys/prctl.h getopt.h)
 AC_HEADER_SYS_WAIT
 AC_HEADER_TIME
 
@@ -688,11 +688,31 @@  if test -z "${setobjs}"; then
 
   AC_CHECK_FUNCS($checkfuncs)
   AC_CHECK_DECLS([basename(char *), ffs, asprintf, vasprintf, snprintf, vsnprintf])
-  AC_CHECK_DECLS([calloc, getenv, getopt, malloc, realloc, sbrk])
+  AC_CHECK_DECLS([calloc, getenv, malloc, realloc, sbrk])
   AC_CHECK_DECLS([strtol, strtoul, strtoll, strtoull])
   AC_CHECK_DECLS([strverscmp])
   AC_CHECK_DECLS([strnlen])
   libiberty_NEED_DECLARATION(canonicalize_file_name)
+
+  saved_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -I${srcdir}/../include"
+  saved_CXXFLAGS="$CXXFLAGS"
+  CXXFLAGS="$CXXFLAGS -I${srcdir}/../include"
+  AC_CHECK_DECLS([optarg, optind, getopt, no_argument, required_argument,
+			getopt_long, _getopt_internal], , ,
+			[[
+#include "ansidecl.h"
+#include "gcc-getopt.h"]])
+  AC_CACHE_CHECK(for struct option, ac_cv_struct_option, [
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#define HAVE_STRUCT_OPTION 1
+#include "ansidecl.h"
+#include "gcc-getopt.h"]], [[struct option option;]])],
+  [ac_cv_struct_option=1],[ac_cv_struct_option=0])])
+  AC_DEFINE_UNQUOTED([HAVE_STRUCT_OPTION], [$ac_cv_struct_option],
+  [Set to 1 if struct option is defined, otherwise to 0.])
+  CFLAGS="$saved_CFLAGS"
+  CXXFLAGS="$saved_CXXFLAGS"
 fi
 
 # Figure out which version of pexecute to use.
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index cbfb2f937ca..2900bc6985f 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -6678,7 +6678,7 @@  is_gnu_v3_mangled_dtor (const char *name)
 
 #ifdef STANDALONE_DEMANGLER
 
-#include "getopt.h"
+#include "gcc-getopt.h"
 #include "dyn-string.h"
 
 static void print_usage (FILE* fp, int exit_value);
diff --git a/libiberty/getopt.c b/libiberty/getopt.c
index 7119b621c12..de8e97dd1cd 100644
--- a/libiberty/getopt.c
+++ b/libiberty/getopt.c
@@ -104,7 +104,7 @@ 
    GNU application programs can use a third alternative mode in which
    they can distinguish the relative order of options and other arguments.  */
 
-#include "getopt.h"
+#include "gcc-getopt.h"
 
 /* For communication from `getopt' to the caller.
    When `getopt' finds an option that takes an argument,
diff --git a/libiberty/getopt1.c b/libiberty/getopt1.c
index 87242472e86..75d077dd489 100644
--- a/libiberty/getopt1.c
+++ b/libiberty/getopt1.c
@@ -33,7 +33,7 @@ 
 
 #include <stdio.h>
 
-#include "getopt.h"
+#include "gcc-getopt.h"
 
 /* Comment out all this code if we are using the GNU C Library, and are not
    actually compiling the library itself.  This code is part of the GNU C