[mingw-gettext: 10/26] Let other binaries have a soft-dep on libintl-8.dll

epienbro epienbro at fedoraproject.org
Tue Mar 6 19:45:08 UTC 2012


commit 219f27c0a38e23f2f881308a2078edbc0ea19288
Author: Erik van Pienbroek <epienbro at fedoraproject.org>
Date:   Sat Oct 16 16:47:07 2010 +0200

    Let other binaries have a soft-dep on libintl-8.dll

 libintl.c            |  367 ++++++++++++++++++++++++++++++++++++++++++++++++++
 libintl.h            |   70 ++++++++++
 mingw32-gettext.spec |   33 ++++-
 3 files changed, 465 insertions(+), 5 deletions(-)
---
diff --git a/libintl.c b/libintl.c
new file mode 100644
index 0000000..b34fe16
--- /dev/null
+++ b/libintl.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2008 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; see the file COPYING.LIB.txt.  If
+ * not, write to the Free Software Foundation, Inc., 51 Franklin
+ * Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef _WIN32
+#  include <windows.h>
+#  include <string.h>
+#else
+#  include <stddef.h>
+#  if !STUB_ONLY
+#    include <dlfcn.h>
+#  endif
+typedef void* HMODULE;
+#endif
+
+#include <string.h>
+
+#include "libintl.h"
+
+const char *_nl_expand_alias(const char *unused) { return NULL; }
+int  _nl_msg_cat_cntr;		/* So that configury thinks it is GNU
+				 * gettext
+				 */
+
+static char * (*p_gettext) (const char *msgid);
+
+static char * (*p_dgettext) (const char *domainname,
+			     const char *msgid);
+
+static char * (*p_dcgettext) (const char *domainname,
+			      const char *msgid,
+			      int         category);
+
+static char * (*p_ngettext) (const char       *msgid1,
+			     const char       *msgid2,
+			     unsigned long int n);
+
+static char * (*p_dngettext) (const char       *domainname,
+			      const char       *msgid1,
+			      const char       *msgid2,
+			      unsigned long int n);
+
+static char * (*p_dcngettext) (const char       *domainname,
+			       const char       *msgid1,
+			       const char       *msgid2,
+			       unsigned long int n,
+			       int               category);
+
+static char * (*p_textdomain) (const char *domainname);
+
+static char * (*p_bindtextdomain) (const char *domainname,
+				   const char *dirname);
+
+static char * (*p_bind_textdomain_codeset) (const char *domainname,
+					    const char *codeset);
+
+static int
+use_intl_dll (HMODULE dll)
+{
+#if !STUB_ONLY
+#  ifdef _WIN32
+#    define LOOKUP(fn) p_##fn = (void *) GetProcAddress (dll, #fn); if (p_##fn == NULL) return 0
+#  else
+#    define LOOKUP(fn) p_##fn = (void *) dlsym (dll, #fn); if (p_##fn == NULL) return 0
+#  endif  /* _WIN32 */
+
+
+  LOOKUP (gettext);
+  LOOKUP (dgettext);
+  LOOKUP (dcgettext);
+  LOOKUP (ngettext);
+  LOOKUP (dngettext);
+  LOOKUP (dcngettext);
+  LOOKUP (textdomain);
+  LOOKUP (bindtextdomain);
+  LOOKUP (bind_textdomain_codeset);
+  
+#undef LOOKUP
+#endif  /* !STUB_ONLY */
+  return 1;
+}
+
+static char *current_domain = NULL;
+
+#define DUMMY(fn, parlist, retval)		\
+static char *					\
+dummy_##fn parlist				\
+{						\
+  return (char *) (retval);			\
+}
+
+DUMMY (gettext,
+       (const char *msgid),
+       msgid)
+
+DUMMY (dgettext, 
+       (const char *domainname,
+	const char *msgid),
+       msgid)
+
+DUMMY (dcgettext,
+       (const char *domainname,
+	const char *msgid,
+	int         category),
+       msgid)
+
+DUMMY (ngettext,
+       (const char       *msgid1,
+	const char       *msgid2,
+	unsigned long int n),
+       n == 1 ? msgid1 : msgid2)
+
+DUMMY (dngettext,
+       (const char       *domainname,
+	const char       *msgid1,
+	const char       *msgid2,
+	unsigned long int n),
+       n == 1 ? msgid1 : msgid2)
+
+DUMMY (dcngettext,
+       (const char       *domainname,
+	const char       *msgid1,
+	const char       *msgid2,
+	unsigned long int n,
+	int               category),
+       n == 1 ? msgid1 : msgid2)
+
+/* GLib requires that textdomain(NULL) returns "messages"
+ * if textdomain() hasn't been called earlier.
+ */
+DUMMY (textdomain,
+       (const char *domainname),
+       (domainname ?
+	(free (current_domain), current_domain = strdup (domainname)) :
+	(current_domain ?
+	 current_domain :
+	 (current_domain = strdup ("messages")))))
+
+/* bindtextdomain() should return the current dirname for the domain,
+ * after possibly changing it. I don't think software usually checks
+ * the return value, though, so just return a dummy string now. This
+ * is the dummy implementation after all, so it hardly matters?
+ */
+DUMMY (bindtextdomain,
+       (const char *domainname,
+	const char *dirname),
+       "/dummy")
+
+/* bind_textdomain_codeset() should return the corrent codeset for the
+ * domain after possibly changing it. Again, this is the dummy
+ * implementation, so just return the codeset argument.
+ */
+DUMMY (bind_textdomain_codeset,
+       (const char *domainname,
+	const char *codeset),
+       codeset)
+
+#undef DUMMY
+
+static void
+use_dummy (void)
+{
+#define USE_DUMMY(fn) p_##fn = dummy_##fn
+
+  USE_DUMMY (gettext);
+  USE_DUMMY (dgettext);
+  USE_DUMMY (dcgettext);
+  USE_DUMMY (ngettext);
+  USE_DUMMY (dngettext);
+  USE_DUMMY (dcngettext);
+  USE_DUMMY (textdomain);
+  USE_DUMMY (bindtextdomain);
+  USE_DUMMY (bind_textdomain_codeset);
+  
+#undef USE_DUMMY
+
+}
+
+#ifdef _WIN32
+
+/* To reduce DLL hijacking risk we look for the libintl DLL in
+ * explicit full paths. We look in two places: The the directory of
+ * the application's exe file, then the directory of the DLL this code
+ * is in. (Those two might be the same, of course, but we don't bother
+ * testing that.)
+ */
+
+static HMODULE
+try_load_from_directory_of_module (HMODULE module,
+				   const char *dll_name)
+{
+  wchar_t buf[MAX_PATH*2];
+  wchar_t *slash;
+  int n;
+
+  n = GetModuleFileNameW (module, buf, MAX_PATH);
+
+  if (n == 0 || n == MAX_PATH)
+    return NULL;
+
+  slash = wcsrchr (buf, L'\\');
+  if (slash)
+    *slash = L'\0';
+
+  wcscat (buf, L"\\");
+  MultiByteToWideChar (CP_ACP, 0, dll_name, -1,
+		       buf + wcslen (buf),
+		       MAX_PATH);
+
+  return LoadLibraryW (buf);
+}
+
+
+static HMODULE
+try_load (const char *dll_name)
+{
+  HMODULE retval = NULL;
+  HMODULE this_module = NULL;
+  typedef BOOL (WINAPI *GetModuleHandleExA_t) (DWORD, LPVOID, HMODULE *);
+  GetModuleHandleExA_t GetModuleHandleExA_p;
+
+  retval = try_load_from_directory_of_module (GetModuleHandle (NULL), dll_name);
+
+  if (retval)
+    return retval;
+
+  GetModuleHandleExA_p =
+    (GetModuleHandleExA_t) GetProcAddress (GetModuleHandle ("kernel32.dll"),
+					   "GetModuleHandleExA");
+
+  if (GetModuleHandleExA_p == NULL ||
+      !(*GetModuleHandleExA_p) (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
+				GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+				&try_load, &this_module))
+    {
+      /* If GetModuleHandleExA() fails, or if it isn't present, use
+       * heuristics that the module handle equals the allocation base
+       * address for the module's code region.
+       */
+      MEMORY_BASIC_INFORMATION mbi;
+
+      if (VirtualQuery (&try_load, &mbi, sizeof (mbi)))
+	this_module = (HMODULE) mbi.AllocationBase;
+    }
+
+  if (this_module)
+    retval = try_load_from_directory_of_module (this_module, dll_name);
+
+  return retval;
+}
+
+#endif
+
+static void
+setup (void)
+{
+  static int beenhere = 0;
+
+  if (!beenhere)
+    {
+#if !STUB_ONLY
+#if defined(_WIN64)
+      /* On 64-bit Windows we have let libtool choose the default name
+       * for the DLL, as we don't need the intl.dll name for backward
+       * compatibility
+       */
+      HMODULE intl_dll = try_load ("libintl-8.dll");
+#  elif defined( _WIN32)
+      /* On 32-bit Windows try both the traditional name intl.dll,
+       * and libintl-8.dll.
+       */
+      HMODULE intl_dll = try_load ("intl.dll");
+      if (intl_dll == NULL)
+	intl_dll = try_load ("libintl-8.dll");
+#  elif defined(__APPLE__) && defined(__MACH__)
+      HMODULE intl_dll = dlopen ("libintl.dylib", RTLD_LAZY);
+#  else
+      HMODULE intl_dll = dlopen ("libintl.so", RTLD_LAZY);
+#  endif
+#else  /* !STUB_ONLY */
+      HMODULE intl_dll = NULL;
+#endif  /* STUB_ONLY */
+
+      if (intl_dll != NULL &&
+	  use_intl_dll (intl_dll))
+	;
+      else
+	use_dummy ();
+
+      beenhere = 1;
+    }
+}
+
+#define IMPLEMENT(fn, parlist, parlist2)	\
+char *						\
+fn parlist					\
+{						\
+  setup ();					\
+  return p_##fn parlist2;			\
+}
+
+IMPLEMENT (gettext,
+	   (const char *msgid),
+	   (msgid))
+
+IMPLEMENT (dgettext,
+	   (const char *domainname,
+	    const char *msgid),
+	   (domainname, msgid))
+
+IMPLEMENT (dcgettext,
+	   (const char *domainname,
+	    const char *msgid,
+	    int         category),
+	   (domainname, msgid, category))
+
+IMPLEMENT (ngettext,
+	   (const char       *msgid1,
+	    const char       *msgid2,
+	    unsigned long int n),
+	   (msgid1, msgid2, n))
+
+IMPLEMENT (dngettext,
+	   (const char       *domainname,
+	    const char       *msgid1,
+	    const char       *msgid2,
+	    unsigned long int n),
+	   (domainname, msgid1, msgid2, n))
+
+IMPLEMENT (dcngettext,
+	   (const char       *domainname,
+	    const char       *msgid1,
+	    const char       *msgid2,
+	    unsigned long int n,
+	    int               category),
+	   (domainname, msgid1, msgid2, n, category))
+
+IMPLEMENT (textdomain,
+	   (const char *domainname),
+	   (domainname))
+
+IMPLEMENT (bindtextdomain,
+	   (const char *domainname,
+	    const char *dirname),
+	   (domainname, dirname))
+
+IMPLEMENT (bind_textdomain_codeset,
+	   (const char *domainname,
+	    const char *codeset),
+	   (domainname, codeset))
+
+#undef IMPLEMENT
diff --git a/libintl.h b/libintl.h
new file mode 100644
index 0000000..82d96e7
--- /dev/null
+++ b/libintl.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; see the file COPYING.LIB.txt.  If
+ * not, write to the Free Software Foundation, Inc., 51 Franklin
+ * Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LIBINTL_H
+#define _LIBINTL_H      1
+
+#include <locale.h>
+
+#ifndef LC_MESSAGES
+# define LC_MESSAGES 1729       /* Use same value as in GNU gettext */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *gettext (const char *msgid);
+
+extern char *dgettext (const char *domainname,
+		       const char *msgid);
+
+extern char *dcgettext (const char *domainname,
+			const char *msgid,
+			int         category);
+
+extern char *ngettext (const char       *msgid1,
+		       const char       *msgid2,
+		       unsigned long int n);
+
+extern char *dngettext (const char       *domainname,
+			const char       *msgid1,
+			const char       *msgid2,
+			unsigned long int n);
+
+extern char *dcngettext (const char       *domainname,
+			 const char       *msgid1,
+			 const char       *msgid2,
+			 unsigned long int n,
+			 int               category);
+
+extern char *textdomain (const char *domainname);
+
+extern char *bindtextdomain (const char *domainname,
+                             const char *dirname);
+
+extern char *bind_textdomain_codeset (const char *domainname,
+				      const char *codeset);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBINTL_H */
diff --git a/mingw32-gettext.spec b/mingw32-gettext.spec
index becb7f1..ab4c306 100644
--- a/mingw32-gettext.spec
+++ b/mingw32-gettext.spec
@@ -6,7 +6,7 @@
 
 Name:      mingw32-gettext
 Version:   0.17
-Release:   12%{?dist}
+Release:   13%{?dist}
 Summary:   GNU libraries and utilities for producing multi-lingual messages
 
 License:   GPLv2+ and LGPLv2+
@@ -15,11 +15,16 @@ URL:       http://www.gnu.org/software/gettext/
 Source0:   http://ftp.gnu.org/pub/gnu/gettext/gettext-%{version}.tar.gz
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
+# Proxy-libintl
+# See http://www.gtk.org/download-windows.html for more details
+Source1:   libintl.c
+Source2:   libintl.h
+
 Patch0:    mingw32-gettext-0.17-gnulib-optarg-symbols.patch
 
 BuildArch: noarch
 
-BuildRequires:  mingw32-filesystem >= 49
+BuildRequires: mingw32-filesystem >= 49
 BuildRequires: mingw32-runtime >= 3.15.1
 BuildRequires: mingw32-gcc
 BuildRequires: mingw32-gcc-c++
@@ -55,6 +60,12 @@ Static version of the MinGW Windows Gettext library.
 
 
 %build
+# Build proxy-libintl manually
+cp %{SOURCE1} .
+cp %{SOURCE2} .
+%{_mingw32_cc} -c libintl.c -o libintl.o -I.
+%{_mingw32_ar} rc libintl.a libintl.o
+
 %{_mingw32_configure} \
   --disable-java \
   --disable-native-java \
@@ -77,6 +88,13 @@ rm -f $RPM_BUILD_ROOT%{_mingw32_datadir}/info/dir
 rm -rf $RPM_BUILD_ROOT%{_mingw32_mandir}/man1/
 rm -rf $RPM_BUILD_ROOT%{_mingw32_mandir}/man3/
 
+# Install the proxy-libintl pieces
+rm -f $RPM_BUILD_ROOT%{_mingw32_libdir}/libintl.la
+rm -f $RPM_BUILD_ROOT%{_mingw32_libdir}/libintl.dll.a
+install -m 0644 intl_win32/libintl.a $RPM_BUILD_ROOT%{_mingw32_libdir}/
+rm -f $RPM_BUILD_ROOT%{_mingw32_includedir}/libintl.h
+install -m 0644 libintl.h $RPM_BUILD_ROOT%{_mingw32_includedir}/
+
 %find_lang %{name} --all-name
 
 
@@ -120,8 +138,9 @@ rm -rf $RPM_BUILD_ROOT
 %{_mingw32_libdir}/libgettextsrc.dll.a
 %{_mingw32_libdir}/libgettextsrc.la
 
-%{_mingw32_libdir}/libintl.dll.a
-%{_mingw32_libdir}/libintl.la
+# This isn't really a static library, but a small wrapper library
+# which adds the ability to have a soft dependency on libintl-8.dll
+%{_mingw32_libdir}/libintl.a
 
 %{_mingw32_docdir}/gettext
 %{_mingw32_docdir}/libasprintf/autosprintf_all.html
@@ -136,10 +155,14 @@ rm -rf $RPM_BUILD_ROOT
 %defattr(-,root,root,-)
 %{_mingw32_libdir}/libasprintf.a
 %{_mingw32_libdir}/libgettextpo.a
-%{_mingw32_libdir}/libintl.a
 
 
 %changelog
+* Sat Oct 16 2010 Erik van Pienbroek <epienbro at fedoraproject.org> - 0.17-13
+- Replaced the libintl import library with a small wrapper library in order
+  to let other binaries have a soft-dependency on libintl-8.dll as proposed
+  on the fedora-mingw mailing list
+
 * Sat Jul 25 2009 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.17-12
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
 


More information about the scm-commits mailing list