From: Dave Korn <dave.korn.cygwin@googlemail.com>
To: Benjamin Kosnik <bkoz@redhat.com>
Cc: libstdc++@gcc.gnu.org, GCC Patches <gcc-patches@gcc.gnu.org>,
Danny Smith <dansmister@gmail.com>,
"Aaron W. LaFramboise (GCC)" <aaronavay62@aaronwl.com>,
Kai Tietz <ktietz70@googlemail.com>,
Dave Korn <dave.korn.cygwin@googlemail.com>
Subject: Libstdc++ as DLL on windows, alternative approach [was Re: cygwin patch review]
Date: Thu, 12 Nov 2009 22:33:00 -0000 [thread overview]
Message-ID: <4AFC8EC3.10502@gmail.com> (raw)
In-Reply-To: <20091019092452.2e271791@mcgee.artheist.org>
[-- Attachment #1: Type: text/plain, Size: 3723 bytes --]
Benjamin Kosnik wrote:
> From older mail thread:
Likewise. I had to take some time away from this to do other stuff, but
I've gotten back to it this week.
> No. There is already visibility markup on libstdc++ headers for this.
> You can just put the attribute visibility bits on namespace std, and be
> done with it.
>
> Here, from include/bits/c++config.h:
>
> # define _GLIBCXX_BEGIN_NAMESPACE(X) namespace X
> _GLIBCXX_VISIBILITY_ATTR(default)
Ok, so as we discussed before, this doesn't currently work. However it does
sound like the right thing to do, so I've spun a new version of the patch that
applies dllimport to the namespace. We could commit this and then open a PR
about dllimport not working on namespaces. It's much smaller and cleaner than
the version that adds markup everywhere, but I doubt I'll be able to fix the
dllimport-vs-namespace bug in time for 4.5. That's not the end of the world;
getting dllimport right is a good optimisation, but we can live with the
compromise of auto-import for now.
Initial test results (c and c++ only) are posted(*) and look right, but I'll
do a clean run on the same source revision for comparison anyway. Note that I
had to patch various testsuite/lib/ files to avoid the current utf-8
problem(**) that would otherwise have provoked many spurious 'excess errors'
warnings. That'll be the subject of a separate patch, I'll do the clean run
using them as well so the comparison is fair.
gcc/ChangeLog:
* configure.ac (USE_CYGWIN_LIBSTDCXX_WRAPPERS): Define to reflect
status of AC_CHECK_FUNC for Cygwin DLL libstdc++ support wrappers.
* configure: Regenerate.
* config.in: Regenerate.
* config/i386/cygwin.h (CXX_WRAP_SPEC_LIST): Define list of --wrap
options for Cygwin DLL libstdc++ support wrappers.
(CXX_WRAP_SPEC_OPT): Define spec to use wrappers or not by default
according to defined value of USE_CYGWIN_LIBSTDCXX_WRAPPERS.
(CXX_WRAP_SPEC): Define entire wrapper spec in or out according to
whether USE_CYGWIN_LIBSTDCXX_WRAPPERS is even defined or not.
(LINK_SPEC): Include CXX_WRAP_SPEC.
* gcc/config/i386/winnt.c (wrapper_strcmp): New qsort helper function.
(i386_find_on_wrapper_list): Check if a function is found on the list
of libstdc++ wrapper options.
(i386_pe_file_end): If we are importing a wrapped function, also emit
an external declaration for the real version.
* config/i386/cygming.opt (muse-libstdc-wrappers): New option for
Cygwin targets. Update copyright year.
* gcc.c (LINK_COMMAND_SPEC): Allow and ignore -static-libstdc++
similarly to -static.
gcc/cp/ChangeLog:
* g++spec.c (SKIPOPT): Delete.
(lang_specific_driver): Do not skip -static-libstdc++ option.
libstdc++-v3/ChangeLog:
* libstdc++-v3/acinclude.m4 (GLIBCXX_ENABLE_SYMVERS): Don't disable
on PE targets.
* libstdc++-v3/configure: Regenerate.
* libstdc++-v3/configure.host: Add libtool DLL options for Cygwin
and MinGW platforms.
* libstdc++-v3/include/bits/c++config (_GLIBCXX_VISIBILITY_ATTR): On
platforms that don't support visibility, allow them to declare a macro
_GLIBCXX_PSEUDO_VISIBILITY that is applied in place of visibility.
* libstdc++-v3/config/os/newlib/os_defines.h
(_GLIBCXX_PSEUDO_VISIBILITY_default): New macro for dllimport.
(_GLIBCXX_PSEUDO_VISIBILITY_hidden): New empty macro.
(_GLIBCXX_PSEUDO_VISIBILITY): Evaluate to one of the above.
* libstdc++-v3/config/os/mingw32/os_defines.h
(_GLIBCXX_PSEUDO_VISIBILITY_default,
_GLIBCXX_PSEUDO_VISIBILITY_hidden,
_GLIBCXX_PSEUDO_VISIBILITY): Likewise.
So, is this any more like OK for head?
cheers,
DaveK
--
(*) - http://gcc.gnu.org/ml/gcc-testresults/2009-11/msg01084.html
(**) - http://gcc.gnu.org/ml/gcc/2009-10/threads.html#00480
[-- Attachment #2: libstdc-dll-vis.diff --]
[-- Type: text/x-c, Size: 12694 bytes --]
Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c (revision 154011)
+++ gcc/gcc.c (working copy)
@@ -766,7 +766,10 @@ proper position among the other output files. */
/* -u* was put back because both BSD and SysV seem to support it. */
/* %{static:} simply prevents an error message if the target machine
- doesn't handle -static. */
+ doesn't handle -static; %{static-libstdc++} is a C++ FE option,
+ handled entirely in cp/g++spec.c, yet we cannot just remove it
+ from the command-line there or it cannot be tested in target spec
+ processing, so we simply ignore it here similarly. */
/* We want %{T*} after %{L*} and %D so that it can be used to specify linker
scripts which exist in user specified directories, or in standard
directories. */
@@ -789,7 +792,7 @@ proper position among the other output files. */
%{flto} %{fwhopr} %l " LINK_PIE_SPEC \
"%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
%{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
- %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
+ %{static:} %{static-libstdc++:} %{L*} %(mfwrap) %(link_libgcc) %o\
%{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
%{fprofile-arcs|fprofile-generate*|coverage:-lgcov}\
%{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
Index: gcc/cp/g++spec.c
===================================================================
--- gcc/cp/g++spec.c (revision 154011)
+++ gcc/cp/g++spec.c (working copy)
@@ -30,8 +30,6 @@ along with GCC; see the file COPYING3. If not see
#define MATHLIB (1<<2)
/* This bit is set if they did `-lc'. */
#define WITHLIBC (1<<3)
-/* Skip this option. */
-#define SKIPOPT (1<<4)
#ifndef MATH_LIBRARY
#define MATH_LIBRARY "-lm"
@@ -211,10 +209,7 @@ lang_specific_driver (int *in_argc, const char *co
else if (strcmp (argv[i], "-static-libgcc") == 0)
shared_libgcc = 0;
else if (strcmp (argv[i], "-static-libstdc++") == 0)
- {
library = library >= 0 ? 2 : library;
- args[i] |= SKIPOPT;
- }
else if (DEFAULT_WORD_SWITCH_TAKES_ARG (&argv[i][1]))
i++;
else
@@ -324,9 +319,6 @@ lang_specific_driver (int *in_argc, const char *co
arglist[j] = "-xnone";
}
- if ((args[i] & SKIPOPT) != 0)
- --j;
-
i++;
j++;
}
Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac (revision 154011)
+++ gcc/configure.ac (working copy)
@@ -2989,6 +2989,25 @@ changequote(,)dnl
i[34567]86-*-* | x86_64-*-*)
changequote([,])dnl
case $target_os in
+ cygwin*)
+ # Full C++ conformance when using a shared libstdc++-v3 requires some
+ # support from the Cygwin DLL, which in more recent versions exports
+ # wrappers to aid in interposing and redirecting operators new, delete,
+ # etc., as per n2800 #17.6.4.6 [replacement.functions]. Check if we
+ # are configuring for a version of Cygwin that exports the wrappers.
+ if test x$host = x$target; then
+ AC_CHECK_FUNC([__wrap__Znaj],[gcc_ac_cygwin_dll_wrappers=yes],[gcc_ac_cygwin_dll_wrappers=no])
+ else
+ # Can't check presence of libc functions during cross-compile, so
+ # we just have to assume we're building for an up-to-date target.
+ gcc_ac_cygwin_dll_wrappers=yes
+ fi
+ AC_DEFINE_UNQUOTED(USE_CYGWIN_LIBSTDCXX_WRAPPERS,
+ [`if test $gcc_ac_cygwin_dll_wrappers = yes; then echo 1; else echo 0; fi`],
+ [Define if you want to generate code by default that assumes that the
+ Cygwin DLL exports wrappers to support libstdc++ function replacement.])
+ esac
+ case $target_os in
cygwin* | pe | mingw32*)
# Recent binutils allows the three-operand form of ".comm" on PE. This
# definition is used unconditionally to initialise the default state of
Index: gcc/config/i386/cygwin.h
===================================================================
--- gcc/config/i386/cygwin.h (revision 154011)
+++ gcc/config/i386/cygwin.h (working copy)
@@ -85,9 +85,41 @@ along with GCC; see the file COPYING3. If not see
%{mwindows:-lgdi32 -lcomdlg32} \
-luser32 -lkernel32 -ladvapi32 -lshell32"
+/* To implement C++ function replacement we always wrap the cxx
+ malloc-like operators. See N2800 #17.6.4.6 [replacement.functions] */
+#define CXX_WRAP_SPEC_LIST "%{!static: %{!static-libstdc++: \
+ --wrap _Znwj \
+ --wrap _Znaj \
+ --wrap _ZdlPv \
+ --wrap _ZdaPv \
+ --wrap _ZnwjRKSt9nothrow_t \
+ --wrap _ZnajRKSt9nothrow_t \
+ --wrap _ZdlPvRKSt9nothrow_t \
+ --wrap _ZdaPvRKSt9nothrow_t \
+ }}"
+
+#if defined (USE_CYGWIN_LIBSTDCXX_WRAPPERS)
+
+#if USE_CYGWIN_LIBSTDCXX_WRAPPERS
+/* Default on, only explict -mno disables. */
+#define CXX_WRAP_SPEC_OPT "!mno-use-libstdc-wrappers"
+#else
+/* Default off, only explict -m enables. */
+#define CXX_WRAP_SPEC_OPT "muse-libstdc-wrappers"
+#endif
+
+#define CXX_WRAP_SPEC "%{" CXX_WRAP_SPEC_OPT ":" CXX_WRAP_SPEC_LIST "}"
+
+#else /* !defined (USE_CYGWIN_LIBSTDCXX_WRAPPERS) */
+
+#define CXX_WRAP_SPEC ""
+
+#endif /* ?defined (USE_CYGWIN_LIBSTDCXX_WRAPPERS) */
+
#define LINK_SPEC "\
%{mwindows:--subsystem windows} \
%{mconsole:--subsystem console} \
+ " CXX_WRAP_SPEC " \
%{shared: %{mdll: %eshared and mdll are not compatible}} \
%{shared: --shared} %{mdll:--dll} \
%{static:-Bstatic} %{!static:-Bdynamic} \
Index: gcc/config/i386/winnt.c
===================================================================
--- gcc/config/i386/winnt.c (revision 154011)
+++ gcc/config/i386/winnt.c (working copy)
@@ -603,6 +603,64 @@ i386_pe_maybe_record_exported_symbol (tree decl, c
export_head = p;
}
+#ifdef CXX_WRAP_SPEC_LIST
+
+/* Hash table equality helper function. */
+
+static int
+wrapper_strcmp (const void *x, const void *y)
+{
+ return !strcmp ((const char *) x, (const char *) y);
+}
+
+/* Search for a function named TARGET in the list of library wrappers
+ we are using, returning a pointer to it if found or NULL if not.
+ This function might be called on quite a few symbols, and we only
+ have the list of names of wrapped functions available to us as a
+ spec string, so first time round we lazily initialise a hash table
+ to make things quicker. */
+
+static const char *
+i386_find_on_wrapper_list (const char *target)
+{
+ static char first_time = 1;
+ static htab_t wrappers;
+
+ if (first_time)
+ {
+ /* Beware that this is not a complicated parser, it assumes
+ that any sequence of non-whitespace beginning with an
+ underscore is one of the wrapped symbols. For now that's
+ adequate to distinguish symbols from spec substitutions
+ and command-line options. */
+ static char wrapper_list_buffer[] = CXX_WRAP_SPEC_LIST;
+ char *bufptr;
+ /* Breaks up the char array into separated strings
+ strings and enter them into the hash table. */
+ wrappers = htab_create_alloc (8, htab_hash_string, wrapper_strcmp,
+ 0, xcalloc, free);
+ for (bufptr = wrapper_list_buffer; *bufptr; ++bufptr)
+ {
+ char *found = NULL;
+ if (ISSPACE (*bufptr))
+ continue;
+ if (*bufptr == '_')
+ found = bufptr;
+ while (*bufptr && !ISSPACE (*bufptr))
+ ++bufptr;
+ if (*bufptr)
+ *bufptr = 0;
+ if (found)
+ *htab_find_slot (wrappers, found, INSERT) = found;
+ }
+ first_time = 0;
+ }
+
+ return (const char *) htab_find (wrappers, target);
+}
+
+#endif /* CXX_WRAP_SPEC_LIST */
+
/* This is called at the end of assembly. For each external function
which has not been defined, we output a declaration now. We also
output the .drectve section. */
@@ -624,6 +682,15 @@ i386_pe_file_end (void)
if (! TREE_ASM_WRITTEN (decl)
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
{
+#ifdef CXX_WRAP_SPEC_LIST
+ /* To ensure the DLL that provides the corresponding real
+ functions is still loaded at runtime, we must reference
+ the real function so that an (unused) import is created. */
+ const char *realsym = i386_find_on_wrapper_list (p->name);
+ if (realsym)
+ i386_pe_declare_function_type (asm_out_file,
+ concat ("__real_", realsym, NULL), TREE_PUBLIC (decl));
+#endif /* CXX_WRAP_SPEC_LIST */
TREE_ASM_WRITTEN (decl) = 1;
i386_pe_declare_function_type (asm_out_file, p->name,
TREE_PUBLIC (decl));
Index: gcc/config/i386/cygming.opt
===================================================================
--- gcc/config/i386/cygming.opt (revision 154011)
+++ gcc/config/i386/cygming.opt (working copy)
@@ -1,6 +1,6 @@
; Cygwin- and MinGW-specific options.
-; Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+; Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc.
;
; This file is part of GCC.
;
@@ -49,3 +49,7 @@ Create GUI application
mpe-aligned-commons
Target Var(use_pe_aligned_common) Init(HAVE_GAS_ALIGNED_COMM)
Use the GNU extension to the PE format for aligned common data
+
+muse-libstdc-wrappers
+Target Condition({defined (USE_CYGWIN_LIBSTDCXX_WRAPPERS)})
+Compile code that relies on Cygwin DLL wrappers to support C++ operator new/delete replacement
Index: libstdc++-v3/configure
===================================================================
--- libstdc++-v3/configure (revision 154011)
+++ libstdc++-v3/configure (working copy)
@@ -58050,7 +58050,7 @@ if test x$enable_symvers = xyes ; then
else
if test $with_gnu_ld = yes ; then
case ${target_os} in
- cygwin* | pe | mingw32* | hpux*)
+ hpux*)
enable_symvers=no ;;
*)
enable_symvers=gnu ;;
Index: libstdc++-v3/configure.host
===================================================================
--- libstdc++-v3/configure.host (revision 154011)
+++ libstdc++-v3/configure.host (working copy)
@@ -209,6 +209,7 @@ case "${host_os}" in
;;
cygwin*)
os_include_dir="os/newlib"
+ OPT_LDFLAGS="${OPT_LDFLAGS} -no-undefined -bindir \$(bindir)"
;;
darwin | darwin[1-7] | darwin[1-7].*)
# On Darwin, performance is improved if libstdc++ is single-module.
@@ -258,6 +259,7 @@ case "${host_os}" in
mingw32*)
os_include_dir="os/mingw32"
error_constants_dir="os/mingw32"
+ OPT_LDFLAGS="${OPT_LDFLAGS} -no-undefined -bindir \$(bindir)"
;;
netbsd*)
os_include_dir="os/bsd/netbsd"
Index: libstdc++-v3/include/bits/c++config
===================================================================
--- libstdc++-v3/include/bits/c++config (revision 154011)
+++ libstdc++-v3/include/bits/c++config (working copy)
@@ -41,6 +41,8 @@
#if _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY
# define _GLIBCXX_VISIBILITY_ATTR(V) __attribute__ ((__visibility__ (#V)))
+#elif defined (_GLIBCXX_PSEUDO_VISIBILITY)
+# define _GLIBCXX_VISIBILITY_ATTR(V) _GLIBCXX_PSEUDO_VISIBILITY(V)
#else
# define _GLIBCXX_VISIBILITY_ATTR(V)
#endif
Index: libstdc++-v3/config/os/newlib/os_defines.h
===================================================================
--- libstdc++-v3/config/os/newlib/os_defines.h (revision 154011)
+++ libstdc++-v3/config/os/newlib/os_defines.h (working copy)
@@ -36,6 +36,15 @@
#ifdef __CYGWIN__
#define _GLIBCXX_GTHREAD_USE_WEAK 0
+#if defined (_GLIBCXX_DLL)
+#define _GLIBCXX_PSEUDO_VISIBILITY_default __attribute__ ((__dllimport__))
+#else
+#define _GLIBCXX_PSEUDO_VISIBILITY_default
+#endif
+#define _GLIBCXX_PSEUDO_VISIBILITY_hidden
+
+#define _GLIBCXX_PSEUDO_VISIBILITY(V) _GLIBCXX_PSEUDO_VISIBILITY_ ## V
+
// See libstdc++/20806.
#define _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM 1
#endif
Index: libstdc++-v3/config/os/mingw32/os_defines.h
===================================================================
--- libstdc++-v3/config/os/mingw32/os_defines.h (revision 154011)
+++ libstdc++-v3/config/os/mingw32/os_defines.h (working copy)
@@ -45,6 +45,15 @@
#undef NOMINMAX
#define NOMINMAX 1
+#if defined (_GLIBCXX_DLL)
+#define _GLIBCXX_PSEUDO_VISIBILITY_default __attribute__ ((__dllimport__))
+#else
+#define _GLIBCXX_PSEUDO_VISIBILITY_default
+#endif
+#define _GLIBCXX_PSEUDO_VISIBILITY_hidden
+
+#define _GLIBCXX_PSEUDO_VISIBILITY(V) _GLIBCXX_PSEUDO_VISIBILITY_ ## V
+
// See libstdc++/20806.
#define _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM 1
Index: libstdc++-v3/acinclude.m4
===================================================================
--- libstdc++-v3/acinclude.m4 (revision 154011)
+++ libstdc++-v3/acinclude.m4 (working copy)
@@ -2737,7 +2737,7 @@ if test x$enable_symvers = xyes ; then
else
if test $with_gnu_ld = yes ; then
case ${target_os} in
- cygwin* | pe | mingw32* | hpux*)
+ hpux*)
enable_symvers=no ;;
*)
enable_symvers=gnu ;;
next parent reply other threads:[~2009-11-12 22:24 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20091019092452.2e271791@mcgee.artheist.org>
2009-11-12 22:33 ` Dave Korn [this message]
2009-11-16 2:57 ` Dave Korn
2009-11-16 3:34 ` Danny Smith
2009-11-16 3:37 ` Dave Korn
2009-11-19 1:25 ` Dave Korn
2009-11-19 17:39 ` Benjamin Kosnik
2009-11-20 16:56 ` Dave Korn
2009-11-21 6:34 ` Danny Smith
2009-11-23 17:47 ` Benjamin Kosnik
2009-11-30 20:21 ` Dave Korn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4AFC8EC3.10502@gmail.com \
--to=dave.korn.cygwin@googlemail.com \
--cc=aaronavay62@aaronwl.com \
--cc=bkoz@redhat.com \
--cc=dansmister@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=ktietz70@googlemail.com \
--cc=libstdc++@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).