[PATCH 7/7] Add support for MSVC

Mike Hommey mh+jemalloc at glandium.org
Mon Apr 30 03:38:31 PDT 2012


From: Mike Hommey <mh at glandium.org>

Tested with MSVC 8 32 and 64 bits.
---
 Makefile.in                                      |   21 +++++++--
 configure.ac                                     |   54 ++++++++++++++++++++--
 include/compat/stdbool.h                         |   16 +++++++
 include/compat/strings.h                         |   22 +++++++++
 include/jemalloc/internal/atomic.h               |   24 ++++++++++
 include/jemalloc/internal/jemalloc_internal.h.in |   23 +++++++--
 include/jemalloc/jemalloc_defs.h.in              |   10 ++++
 src/jemalloc.c                                   |   11 ++++-
 src/tsd.c                                        |    8 ++++
 9 files changed, 173 insertions(+), 16 deletions(-)
 create mode 100644 include/compat/stdbool.h
 create mode 100644 include/compat/strings.h

diff --git a/Makefile.in b/Makefile.in
index a351a1f..08541a7 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -26,9 +26,11 @@ abs_objroot := @abs_objroot@
 CPPFLAGS := @CPPFLAGS@ -I$(srcroot)include -I$(objroot)include
 CFLAGS := @CFLAGS@
 LDFLAGS := @LDFLAGS@
+EXTRA_LDFLAGS := @EXTRA_LDFLAGS@
 LIBS := @LIBS@
 RPATH_EXTRA := @RPATH_EXTRA@
 SO := @so@
+IMPORTLIB := @importlib@
 O := @o@
 A := @a@
 EXE := @exe@
@@ -49,6 +51,9 @@ enable_experimental := @enable_experimental@
 DSO_LDFLAGS = @DSO_LDFLAGS@
 SOREV = @SOREV@
 PIC_CFLAGS = @PIC_CFLAGS@
+CTARGET = @CTARGET@
+LDTARGET = @LDTARGET@
+MKLIB = @MKLIB@
 
 ifeq (macho, $(ABI))
 TEST_LIBRARY_PATH := DYLD_FALLBACK_LIBRARY_PATH="$(objroot)lib"
@@ -77,9 +82,13 @@ CSRCS := $(srcroot)src/jemalloc.c $(srcroot)src/arena.c $(srcroot)src/atomic.c \
 ifeq (macho, $(ABI))
 CSRCS += $(srcroot)src/zone.c
 endif
+ifeq ($(IMPORTLIB),$(SO))
 STATIC_LIBS := $(objroot)lib/$(LIBJEMALLOC).$(A)
+endif
 ifdef PIC_CFLAGS
 STATIC_LIBS += $(objroot)lib/$(LIBJEMALLOC)_pic.$(A)
+else
+STATIC_LIBS += $(objroot)lib/$(LIBJEMALLOC)_s.$(A)
 endif
 DSOS := $(objroot)lib/$(LIBJEMALLOC).$(SOREV)
 ifneq ($(SOREV),$(SO))
@@ -129,6 +138,9 @@ $(CPICOBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.c
 $(CPICOBJS): CFLAGS += $(PIC_CFLAGS)
 $(CTESTOBJS): $(objroot)test/%.$(O): $(srcroot)test/%.c
 $(CTESTOBJS): CPPFLAGS += -I$(objroot)test
+ifneq ($(IMPORTLIB),$(SO))
+$(COBJS): CPPFLAGS += -DDLLEXPORT
+endif
 
 # Dependencies
 HEADER_DIRS = $(srcroot)include/jemalloc/internal \
@@ -139,7 +151,7 @@ $(CTESTOBJS): $(objroot)test/jemalloc_test.h
 
 $(COBJS) $(CPICOBJS) $(CTESTOBJS): %.$(O):
 	@mkdir -p $(@D)
-	$(CC) $(CFLAGS) -c $(CPPFLAGS) -o $@ $<
+	$(CC) $(CFLAGS) -c $(CPPFLAGS) $(CTARGET) $<
 
 ifneq ($(SOREV),$(SO))
 %.$(SO) : %.$(SOREV)
@@ -149,20 +161,21 @@ endif
 
 $(objroot)lib/$(LIBJEMALLOC).$(SOREV) : $(if $(PIC_CFLAGS),$(CPICOBJS),$(COBJS))
 	@mkdir -p $(@D)
-	$(CC) $(DSO_LDFLAGS) $(call RPATH,$(RPATH_EXTRA)) -o $@ $+ $(LDFLAGS) $(LIBS)
+	$(CC) $(DSO_LDFLAGS) $(call RPATH,$(RPATH_EXTRA)) $(LDTARGET) $+ $(LDFLAGS) $(LIBS) $(EXTRA_LDFLAGS)
 
 $(objroot)lib/$(LIBJEMALLOC)_pic.$(A) : $(CPICOBJS)
 $(objroot)lib/$(LIBJEMALLOC).$(A) : $(COBJS)
+$(objroot)lib/$(LIBJEMALLOC)_s.$(A) : $(COBJS)
 
 $(STATIC_LIBS):
 	@mkdir -p $(@D)
-	ar crus $@ $+
+	$(MKLIB) $+
 
 $(objroot)test/bitmap$(EXE): $(objroot)src/bitmap.$(O)
 
 $(objroot)test/%$(EXE): $(objroot)test/%.$(O) $(objroot)src/util.$(O) $(DSOS)
 	@mkdir -p $(@D)
-	$(CC) -o $@ $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) -L$(objroot)lib -ljemalloc$(install_suffix) $(filter -lpthread,$(LIBS))
+	$(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(filter -lpthread,$(LIBS)) $(EXTRA_LDFLAGS)
 
 build_lib_shared: $(DSOS)
 build_lib_static: $(STATIC_LIBS)
diff --git a/configure.ac b/configure.ac
index 6e74238..500e21c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -111,6 +111,19 @@ dnl If CFLAGS isn't defined, set CFLAGS to something reasonable.  Otherwise,
 dnl just prevent autoconf from molesting CFLAGS.
 CFLAGS=$CFLAGS
 AC_PROG_CC
+if test "x$GCC" != "xyes" ; then
+  AC_CACHE_CHECK([whether compiler is MSVC],
+                 [je_cv_msvc],
+                 [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
+                                                     [
+#ifndef _MSC_VER
+  int fail[-1];
+#endif
+])],
+                               [je_cv_msvc=yes],
+                               [je_cv_msvc=no])])
+fi
+
 if test "x$CFLAGS" = "x" ; then
   no_CFLAGS="yes"
   if test "x$GCC" = "xyes" ; then
@@ -118,6 +131,12 @@ if test "x$CFLAGS" = "x" ; then
     JE_CFLAGS_APPEND([-Wall])
     JE_CFLAGS_APPEND([-pipe])
     JE_CFLAGS_APPEND([-g3])
+  elif test "x$je_cv_msvc" = "xyes" ; then
+    CC="$CC -nologo"
+    JE_CFLAGS_APPEND([-Zi])
+    JE_CFLAGS_APPEND([-MT])
+    JE_CFLAGS_APPEND([-W3])
+    CPPFLAGS="$CPPFLAGS -I${srcroot}/include/compat"
   fi
 fi
 dnl Append EXTRA_CFLAGS to CFLAGS, if defined.
@@ -195,6 +214,7 @@ AC_DEFINE_UNQUOTED([CPU_SPINWAIT], [$CPU_SPINWAIT])
 
 LD_PRELOAD_VAR="LD_PRELOAD"
 so="so"
+importlib="${so}"
 o="$ac_objext"
 a="a"
 exe="$ac_exeext"
@@ -203,9 +223,10 @@ DSO_LDFLAGS='-shared -Wl,-soname,$(@F)'
 RPATH='-Wl,-rpath,$(1)'
 SOREV="${so}.${rev}"
 PIC_CFLAGS='-fPIC -DPIC'
-
-dnl Heap profiling uses the log(3) function.
-LIBS="$LIBS -lm"
+CTARGET='-o $@'
+LDTARGET='-o $@'
+EXTRA_LDFLAGS=
+MKLIB='ar crus $@'
 
 dnl Platform-specific settings.  abi and RPATH can probably be determined
 dnl programmatically, but doing so is error-prone, which makes it generally
@@ -223,6 +244,7 @@ case "${host}" in
 	RPATH=""
 	LD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES"
 	so="dylib"
+	importlib="${so}"
 	force_tls="0"
 	DSO_LDFLAGS='-shared -Wl,-dylib_install_name,$(@F)'
 	SOREV="${rev}.${so}"
@@ -278,7 +300,17 @@ case "${host}" in
 	force_tls="0"
 	RPATH=""
 	so="dll"
-	DSO_LDFLAGS="-shared"
+	if test "x$je_cv_msvc" = "xyes" ; then
+	  importlib="lib"
+	  DSO_LDFLAGS="-LD"
+	  EXTRA_LDFLAGS="-link -DEBUG"
+	  CTARGET='-Fo$@'
+	  LDTARGET='-Fe$@'
+	  MKLIB='lib -nologo -out:$@'
+        else
+	  importlib="${so}"
+	  DSO_LDFLAGS="-shared"
+	fi
 	a="lib"
 	libprefix=""
 	SOREV="${so}"
@@ -293,13 +325,23 @@ AC_SUBST([abi])
 AC_SUBST([RPATH])
 AC_SUBST([LD_PRELOAD_VAR])
 AC_SUBST([so])
+AC_SUBST([importlib])
 AC_SUBST([o])
 AC_SUBST([a])
 AC_SUBST([exe])
 AC_SUBST([libprefix])
 AC_SUBST([DSO_LDFLAGS])
+AC_SUBST([EXTRA_LDFLAGS])
 AC_SUBST([SOREV])
 AC_SUBST([PIC_CFLAGS])
+AC_SUBST([CTARGET])
+AC_SUBST([LDTARGET])
+AC_SUBST([MKLIB])
+
+if test "x$abi" != "xpecoff"; then
+  dnl Heap profiling uses the log(3) function.
+  LIBS="$LIBS -lm"
+fi
 
 JE_COMPILABLE([__attribute__ syntax],
               [static __attribute__((unused)) void foo(void){}],
@@ -530,6 +572,8 @@ if test "x$enable_debug" = "x0" -a "x$no_CFLAGS" = "xyes" ; then
     if test "x$GCC" = "xyes" ; then
       JE_CFLAGS_APPEND([-O3])
       JE_CFLAGS_APPEND([-funroll-loops])
+    elif test "x$je_cv_msvc" = "xyes" ; then
+      JE_CFLAGS_APPEND([-O2])
     else
       JE_CFLAGS_APPEND([-O])
     fi
@@ -833,11 +877,11 @@ AC_CACHE_CHECK([STATIC_PAGE_SHIFT],
                [je_cv_static_page_shift],
                AC_RUN_IFELSE([AC_LANG_PROGRAM(
 [[
+#include <strings.h>
 #ifdef _WIN32
 #include <windows.h>
 #else
 #include <unistd.h>
-#include <strings.h>
 #endif
 #include <stdio.h>
 ]],
diff --git a/include/compat/stdbool.h b/include/compat/stdbool.h
new file mode 100644
index 0000000..da9ee8b
--- /dev/null
+++ b/include/compat/stdbool.h
@@ -0,0 +1,16 @@
+#ifndef stdbool_h
+#define stdbool_h
+
+#include <wtypes.h>
+
+/* MSVC doesn't define _Bool or bool in C, but does have BOOL */
+/* Note this doesn't pass autoconf's test because (bool) 0.5 != true */
+typedef BOOL _Bool;
+
+#define bool _Bool
+#define true 1
+#define false 0
+
+#define __bool_true_false_are_defined 1
+
+#endif /* stdbool_h */
diff --git a/include/compat/strings.h b/include/compat/strings.h
new file mode 100644
index 0000000..6ad8039
--- /dev/null
+++ b/include/compat/strings.h
@@ -0,0 +1,22 @@
+#ifndef strings_h
+#define strings_h
+
+/* MSVC doesn't define ffs/ffsl. This dummy strings.h header is provided
+ * for both */
+#include <intrin.h>
+#pragma intrinsic(_BitScanForward)
+static __forceinline int ffsl(long x)
+{
+	unsigned long i;
+
+	if (_BitScanForward(&i, x))
+		return (i + 1);
+	return (0);
+}
+
+static __forceinline int ffs(int x)
+{
+	return ffsl(x);
+}
+
+#endif
diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic.h
index 016c472..4b6f623 100644
--- a/include/jemalloc/internal/atomic.h
+++ b/include/jemalloc/internal/atomic.h
@@ -47,6 +47,18 @@ atomic_sub_uint64(uint64_t *p, uint64_t x)
 
 	return (__sync_sub_and_fetch(p, x));
 }
+#elif (defined(_MSC_VER))
+JEMALLOC_INLINE uint64_t
+atomic_add_uint64(uint64_t *p, uint64_t x)
+{
+       return InterlockedExchangeAdd64(p, x);
+}
+
+JEMALLOC_INLINE uint64_t
+atomic_sub_uint64(uint64_t *p, uint64_t x)
+{
+       return InterlockedExchangeAdd64(p, -x);
+}
 #elif (defined(JEMALLOC_OSATOMIC))
 JEMALLOC_INLINE uint64_t
 atomic_add_uint64(uint64_t *p, uint64_t x)
@@ -145,6 +157,18 @@ atomic_sub_uint32(uint32_t *p, uint32_t x)
 
 	return (__sync_sub_and_fetch(p, x));
 }
+#elif (defined(_MSC_VER))
+JEMALLOC_INLINE uint32_t
+atomic_add_uint32(uint32_t *p, uint32_t x)
+{
+       return InterlockedExchangeAdd(p, x);
+}
+
+JEMALLOC_INLINE uint32_t
+atomic_sub_uint32(uint32_t *p, uint32_t x)
+{
+       return InterlockedExchangeAdd(p, -x);
+}
 #elif (defined(JEMALLOC_OSATOMIC))
 JEMALLOC_INLINE uint32_t
 atomic_add_uint32(uint32_t *p, uint32_t x)
diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in
index d4c4b4c..97c1794 100644
--- a/include/jemalloc/internal/jemalloc_internal.h.in
+++ b/include/jemalloc/internal/jemalloc_internal.h.in
@@ -1,6 +1,5 @@
 #ifndef JEMALLOC_INTERNAL_H
 #define JEMALLOC_INTERNAL_H
-#include <sys/param.h>
 #include <math.h>
 #ifdef _WIN32
 #  include <windows.h>
@@ -13,6 +12,7 @@
 #  undef ERANGE
 #  define ERANGE ERROR_INVALID_DATA
 #else
+#  include <sys/param.h>
 #  include <sys/mman.h>
 #  include <sys/syscall.h>
 #  if !defined(SYS_write) && defined(__NR_write)
@@ -41,7 +41,17 @@
 #include <string.h>
 #include <strings.h>
 #include <ctype.h>
-#include <unistd.h>
+#ifdef _MSC_VER
+#  include <io.h>
+typedef intptr_t ssize_t;
+#  define PATH_MAX 1024
+#  define STDERR_FILENO 2
+#  define __func__ __FUNCTION__
+/* Disable warnings about deprecated system functions */
+#  pragma warning(disable: 4996)
+#else
+#  include <unistd.h>
+#endif
 #include <fcntl.h>
 
 #define	JEMALLOC_NO_DEMANGLE
@@ -221,6 +231,9 @@ static const bool config_ivsalloc =
 #else
 #  define JEMALLOC_ENABLE_INLINE
 #  define JEMALLOC_INLINE static inline
+#  ifdef _MSC_VER
+#    define inline _inline
+#  endif
 #endif
 
 /* Smallest size class to support. */
@@ -232,7 +245,7 @@ static const bool config_ivsalloc =
  * classes).
  */
 #ifndef LG_QUANTUM
-#  ifdef __i386__
+#  if (defined(__i386__) || defined(_M_IX86))
 #    define LG_QUANTUM		4
 #  endif
 #  ifdef __ia64__
@@ -244,7 +257,7 @@ static const bool config_ivsalloc =
 #  ifdef __sparc64__
 #    define LG_QUANTUM		4
 #  endif
-#  if (defined(__amd64__) || defined(__x86_64__))
+#  if (defined(__amd64__) || defined(__x86_64__) || defined(_M_X64))
 #    define LG_QUANTUM		4
 #  endif
 #  ifdef __arm__
@@ -296,7 +309,7 @@ static const bool config_ivsalloc =
  * In addition, this controls the spacing of cacheline-spaced size classes.
  */
 #define	LG_CACHELINE		6
-#define	CACHELINE		((size_t)(1U << LG_CACHELINE))
+#define	CACHELINE		64
 #define	CACHELINE_MASK		(CACHELINE - 1)
 
 /* Return the smallest cacheline multiple that is >= s. */
diff --git a/include/jemalloc/jemalloc_defs.h.in b/include/jemalloc/jemalloc_defs.h.in
index 3e1f047..f110ed3 100644
--- a/include/jemalloc/jemalloc_defs.h.in
+++ b/include/jemalloc/jemalloc_defs.h.in
@@ -109,6 +109,16 @@
 #  define JEMALLOC_ALIGNED(s) JEMALLOC_ATTR(aligned(s))
 #  define JEMALLOC_SECTION(s) JEMALLOC_ATTR(section(s))
 #  define JEMALLOC_NOINLINE JEMALLOC_ATTR(noinline)
+#elif _MSC_VER
+#  define JEMALLOC_ATTR(s)
+#ifdef DLLEXPORT
+#  define EXPORT __declspec(dllexport)
+#else
+#  define EXPORT __declspec(dllimport)
+#endif
+#  define JEMALLOC_ALIGNED(s) __declspec(align(s))
+#  define JEMALLOC_SECTION(s) __declspec(allocate(s))
+#  define JEMALLOC_NOINLINE __declspec(noinline)
 #else
 #  define JEMALLOC_ATTR(s)
 #  define EXPORT
diff --git a/src/jemalloc.c b/src/jemalloc.c
index fa24b05..40c775d 100644
--- a/src/jemalloc.c
+++ b/src/jemalloc.c
@@ -56,12 +56,19 @@ static bool			malloc_initializer = NO_INITIALIZER;
 static malloc_mutex_t	init_lock;
 
 JEMALLOC_ATTR(constructor)
-static void
-init_init_lock()
+static void WINAPI
+_init_init_lock(void)
 {
 
 	malloc_mutex_init(&init_lock);
 }
+
+#ifdef _MSC_VER
+#  pragma section(".CRT$XCU", read)
+JEMALLOC_SECTION(".CRT$XCU") JEMALLOC_ATTR(used)
+static const void (WINAPI *init_init_lock)(void) = _init_init_lock;
+#endif
+
 #else
 static malloc_mutex_t	init_lock = MALLOC_MUTEX_INITIALIZER;
 #endif
diff --git a/src/tsd.c b/src/tsd.c
index cee57c9..84492b3 100644
--- a/src/tsd.c
+++ b/src/tsd.c
@@ -93,6 +93,14 @@ _tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 	return (true);
 }
 
+#ifdef _MSC_VER
+#  ifdef _M_IX86
+#    pragma comment(linker, "/INCLUDE:__tls_used")
+#  else
+#    pragma comment(linker, "/INCLUDE:_tls_used")
+#  endif
+#  pragma section(".CRT$XLY",long,read)
+#endif
 JEMALLOC_SECTION(".CRT$XLY") JEMALLOC_ATTR(used)
 static const BOOL	(WINAPI *tls_callback)(HINSTANCE hinstDLL,
     DWORD fdwReason, LPVOID lpvReserved) = _tls_callback;
-- 
1.7.10




More information about the jemalloc-discuss mailing list