CPPFLAGS="$LTDLINCL $CPPFLAGS"
-AT_DATA([module.h],
-[[#include <exception>
+# Win32 (and cygwin) notes
+# ------------------------
+# When using C++ and Win32 DLLs, data types used in the DLL's interface
+# which are other-than-POD, must have vtables, typeinfo, and other
+# elements resolved when the client is linked. This includes exception
+# classes. Therefore, the exception class "modexc" thrown by the
+# dynamically-loaded module must be defined in a separate DLL, to which
+# both that module and main must be directly linked; hence, the 'common'
+# library. Not using a 'common' library in this manner represents an
+# ODR violation, unless the platform's runtime loader is capable of
+# rationalizing vague linkage items such as vtables, typeinfo, and
+# typename elements) at runtime. The Win32 loader is not capable of
+# this, but some ELF loaders appear to be.
+#
+# Similar treatment is not necessary for liba (e.g. the libexc
+# exception class), because that library is not dynamically loaded. As a
+# consequence, vague linkage items for the class libexc are resolved at
+# link time using the vague linkage rules, for both Win32 and other
+# (e.g. ELF) platforms.
+#
+# Also, when linking a C++ DLL with another C++ DLL, some versions of
+# the GNU toolchain on Win32 (or cygwin) mistakenly re-export symbols
+# that were imported from the other DLL, when the client DLL is linked
+# using -export-all-symbols. Similar issues MAY also arise with those
+# versions of the GNU toolchain if using the libtool link flags
+# -export-symbols LIST or -export-symbols-regex REGEX, if any symbols
+# from the dependency, rather than client, library are listed (or match
+# the regex). However, in this test, none of these situations apply,
+# so we don't directly address it. Otherwise, the correct mechanism
+# would be to avoid all of those flags, and instead explicitly decorate
+# all symbols with appropriate __attribute__ ((dllexport)) or
+# __attribute__ ((dllimport)) flags when building the DLLs and the
+# clients.
+#
+# For more information, see these two threads:
+# http://lists.gnu.org/archive/html/bug-libtool/2010-06/msg00069.html
+# http://cygwin.com/ml/cygwin/2010-06/msg00392.html
+# To sum up: C++ is complicated.
+AT_DATA([common.h],
+[[#ifndef LIBTOOL_TEST_COMMON_HEADER
+#define LIBTOOL_TEST_COMMON_HEADER
+
+#include <exception>
#include <string>
-class modexc : public std::exception {
+
+#if defined(__CYGWIN__) || defined(_WIN32)
+# if defined(DLL_EXPORT) || defined(USING_COMMON_DLL)
+# if defined(LIBTOOL_TEST_IN_COMMON)
+# define COMMON_IMPEXP __attribute__ ((dllexport))
+# else
+# define COMMON_IMPEXP __attribute__ ((dllimport))
+# endif
+# else
+# define COMMON_IMPEXP
+# endif
+#else
+# define COMMON_IMPEXP
+#endif
+
+class COMMON_IMPEXP modexc : public std::exception {
public:
modexc (std::string str) : message (str) { }
~modexc () throw () { }
private:
std::string message;
};
-extern "C" int modfoo () throw (modexc);
+
+extern "C" int COMMON_IMPEXP common_dummy (void);
+#endif
+]])
+
+AT_DATA([common.cpp],
+[[#define LIBTOOL_TEST_IN_COMMON
+#include "common.h"
+
+extern "C"
+int common_dummy (void)
+{
+ return 0;
+}
+]])
+
+AT_DATA([module.h],
+[[#include "common.h"
+
+#if defined(__CYGWIN__) || defined(_WIN32)
+# if defined(DLL_EXPORT) || defined(USING_MODULE_DLL)
+# if defined(LIBTOOL_TEST_IN_MODULE)
+# define MODULE_IMPEXP __attribute__ ((dllexport))
+# else
+# define MODULE_IMPEXP __attribute__ ((dllimport))
+# endif
+# else
+# define MODULE_IMPEXP
+# endif
+#else
+# define MODULE_IMPEXP
+#endif
+
+extern "C" int MODULE_IMPEXP modfoo () throw (modexc);
]])
AT_DATA([module.cpp],
[[#include <iostream>
+#define LIBTOOL_TEST_IN_MODULE
#include "module.h"
int modbar (void) throw (modexc)
AT_DATA([lib.h],
[[#include <exception>
#include <string>
-class libexc : public std::exception {
+
+
+#if defined(__CYGWIN__) || defined(_WIN32)
+# if defined(DLL_EXPORT) || defined(USING_LIB_DLL)
+# if defined(LIBTOOL_TEST_IN_LIB)
+# define LIB_IMPEXP __attribute__ ((dllexport))
+# else
+# define LIB_IMPEXP __attribute__ ((dllimport))
+# endif
+# else
+# define LIB_IMPEXP
+# endif
+#else
+# define LIB_IMPEXP
+#endif
+
+class LIB_IMPEXP libexc : public std::exception {
public:
libexc (std::string str) : message (str) { }
~libexc () throw () { }
private:
std::string message;
};
-int libfoo () throw (libexc);
+int LIB_IMPEXP libfoo () throw (libexc);
]])
AT_DATA([lib.cpp],
[[#include <iostream>
+#define LIBTOOL_TEST_IN_LIB
#include "lib.h"
int libbar (void) throw (libexc)
#include <iostream>
#include <exception>
#include <string>
+#include "common.h"
#include "lib.h"
#include "module.h"
mkdir l m $inst $libdir $bindir $moddir
# If the C++ compiler isn't capable, don't bother.
-AT_CHECK([$CXX $CPPFLAGS $CXXFLAGS -c main.cpp || exit 77], [], [ignore], [ignore])
+AT_CHECK([$CXX $CPPFLAGS $CXXFLAGS -DUSING_COMMON_DLL -DUSING_MODULE_DLL -DUSING_LIB_DLL -c main.cpp || exit 77], [], [ignore], [ignore])
-for file in lib.cpp module.cpp; do
- AT_CHECK([$LIBTOOL --mode=compile --tag=CXX $CXX $CPPFLAGS $CXXFLAGS -c $file],
+AT_CHECK([$LIBTOOL --mode=compile --tag=CXX $CXX $CPPFLAGS $CXXFLAGS -c common.cpp],
+ [], [ignore], [ignore])
+AT_CHECK([$LIBTOOL --mode=compile --tag=CXX $CXX $CPPFLAGS $CXXFLAGS -c lib.cpp],
+ [], [ignore], [ignore])
+AT_CHECK([$LIBTOOL --mode=compile --tag=CXX $CXX $CPPFLAGS $CXXFLAGS -DUSING_COMMON_DLL -c module.cpp],
[], [ignore], [ignore])
-done
+
+AT_CHECK([$LIBTOOL --mode=link --tag=CXX $CXX $CXXFLAGS $LDFLAGS -o l/libcommon.la ]dnl
+ [common.lo -no-undefined -version-info 1:0:0 -rpath $libdir],
+ [], [ignore], [ignore])
AT_CHECK([$LIBTOOL --mode=link --tag=CXX $CXX $CXXFLAGS $LDFLAGS -o l/liba.la ]dnl
[lib.lo -no-undefined -version-info 1:0:0 -rpath $libdir],
[], [ignore], [ignore])
AT_CHECK([$LIBTOOL --mode=link --tag=CXX $CXX $CXXFLAGS $LDFLAGS -o m/module.la ]dnl
- [module.lo -module -avoid-version -no-undefined -rpath $moddir],
+ [module.lo l/libcommon.la -module -avoid-version -no-undefined -rpath $moddir],
[], [ignore], [ignore])
# We need -export-dynamic for the exception handling in modules to work.
AT_CHECK([$LIBTOOL --mode=link --tag=CXX $CXX $CXXFLAGS $LDFLAGS -o main$EXEEXT ]dnl
- [main.$OBJEXT l/liba.la -dlopen m/module.la $LIBLTDL -export-dynamic],
+ [main.$OBJEXT l/liba.la l/libcommon.la -dlopen m/module.la $LIBLTDL -export-dynamic],
[], [ignore], [ignore])
LT_AT_NOINST_EXEC_CHECK([./main], [-dlopen m/module.la], [], [ignore], [ignore])
+AT_CHECK([$LIBTOOL --mode=install cp l/libcommon.la $libdir],
+ [], [ignore], [ignore])
AT_CHECK([$LIBTOOL --mode=install cp l/liba.la $libdir],
[], [ignore], [ignore])
AT_CHECK([$LIBTOOL --mode=install cp m/module.la $moddir],