Commit c6e48fef4382ed9fc8113733fb6e2b960506728d

Edward Thomson 2019-02-17T21:51:34

regex: allow regex selection in cmake Users can now select which regex implementation they want to use: one of the system `regcomp_l`, the system PCRE, the builtin PCRE or the system's `regcomp`. By default the system `regcomp_l` will be used if it exists, otherwise the system PCRE will be used. If neither of those exist, then the builtin PCRE implementation will be used. The system's `regcomp` is not used by default due to problems with locales.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 88eb9ec..f423b82 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -65,6 +65,7 @@ OPTION(DEBUG_POOL			"Enable debug pool allocator"				OFF)
 OPTION(ENABLE_WERROR			"Enable compilation with -Werror"			OFF)
 OPTION(USE_BUNDLED_ZLIB    		"Use the bundled version of zlib"			OFF)
 OPTION(DEPRECATE_HARD			"Do not include deprecated functions in the library"	OFF)
+   SET(REGEX				"" CACHE STRING "Regular expression implementation. One of regcomp_l, pcre, regcomp, or builtin.")
 
 IF (UNIX AND NOT APPLE)
 	OPTION(ENABLE_REPRODUCIBLE_BUILDS "Enable reproducible builds"				OFF)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4cdfe23..6379495 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -48,23 +48,6 @@ IF (ENABLE_TRACE STREQUAL "ON")
 ENDIF()
 ADD_FEATURE_INFO(tracing GIT_TRACE "tracing support")
 
-# Use `regcomp_l` if available
-CHECK_SYMBOL_EXISTS(regcomp_l "regex.h;xlocale.h" HAVE_REGCOMP_L)
-IF (HAVE_REGCOMP_L)
-	SET(GIT_USE_REGCOMP_L 1)
-ENDIF ()
-
-# Otherwise, we either want to use system's `regcomp` or our
-# bundled regcomp code, if system doesn't provide `regcomp`.
-IF(NOT HAVE_REGCOMP_L)
-	CHECK_FUNCTION_EXISTS(regcomp HAVE_REGCOMP)
-	IF(NOT HAVE_REGCOMP)
-		ADD_SUBDIRECTORY("${libgit2_SOURCE_DIR}/deps/regex" "${libgit2_BINARY_DIR}/deps/regex")
-		LIST(APPEND LIBGIT2_INCLUDES "${libgit2_SOURCE_DIR}/deps/regex")
-		LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:regex>)
-	ENDIF()
-ENDIF()
-
 CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS)
 IF (HAVE_FUTIMENS)
 	SET(GIT_USE_FUTIMENS 1)
@@ -306,14 +289,38 @@ ELSE()
 	MESSAGE(FATAL_ERROR "Asked for unknown SHA1 backend ${SHA1_BACKEND}")
 ENDIF()
 
-# Include PCRE and its POSIX regex compatibility layer when it is required
-IF (HAVE_REGCOMP_L)
+# Specify regular expression implementation
+IF(REGEX STREQUAL "")
+	CHECK_SYMBOL_EXISTS(regcomp_l "regex.h;xlocale.h" HAVE_REGCOMP_L)
+	CHECK_SYMBOL_EXISTS(pcre_regcomp "pcreposix.h" HAVE_PCRE)
+
+	IF(HAVE_REGCOMP_L)
+		SET(REGEX "regcomp_l")
+	ELSEIF(HAVE_PCRE)
+		SET(REGEX "pcre")
+	ELSE()
+		SET(REGEX "builtin")
+	ENDIF()
+ENDIF()
+
+IF(REGEX STREQUAL "regcomp_l")
 	ADD_FEATURE_INFO(regex ON "using system regcomp_l")
-ELSE()
+	SET(GIT_REGEX_REGCOMP_L 1)
+ELSEIF(REGEX STREQUAL "pcre")
+	ADD_FEATURE_INFO(regex ON "using system PCRE")
+	SET(GIT_REGEX_PCRE 1)
+ELSEIF(REGEX STREQUAL "regcomp")
+	ADD_FEATURE_INFO(regex ON "using system regcomp")
+	SET(GIT_REGEX_REGCOMP 1)
+ELSEIF(REGEX STREQUAL "builtin")
+	ADD_FEATURE_INFO(regex ON "using bundled PCRE")
+	SET(GIT_REGEX_PCRE 1)
+
 	ADD_SUBDIRECTORY("${libgit2_SOURCE_DIR}/deps/pcre" "${libgit2_BINARY_DIR}/deps/pcre")
 	LIST(APPEND LIBGIT2_INCLUDES "${libgit2_SOURCE_DIR}/deps/pcre")
 	LIST(APPEND LIBGIT2_OBJECTS $<TARGET_OBJECTS:pcre>)
-	ADD_FEATURE_INFO(regex ON "using bundled PCRE")
+ELSE()
+	MESSAGE(FATAL_ERROR "The REGEX option provided is not supported")
 ENDIF()
 
 # Optional external dependency: http-parser
diff --git a/src/features.h.in b/src/features.h.in
index 694a61c..fdc7594 100644
--- a/src/features.h.in
+++ b/src/features.h.in
@@ -15,7 +15,10 @@
 #cmakedefine GIT_USE_STAT_MTIMESPEC 1
 #cmakedefine GIT_USE_STAT_MTIME_NSEC 1
 #cmakedefine GIT_USE_FUTIMENS 1
-#cmakedefine GIT_USE_REGCOMP_L 1
+
+#cmakedefine GIT_REGEX_REGCOMP_L
+#cmakedefine GIT_REGEX_REGCOMP
+#cmakedefine GIT_REGEX_PCRE
 
 #cmakedefine GIT_SSH 1
 #cmakedefine GIT_SSH_MEMORY_CREDENTIALS 1
diff --git a/src/posix_regex.h b/src/posix_regex.h
index c39631e..5d0342e 100644
--- a/src/posix_regex.h
+++ b/src/posix_regex.h
@@ -10,32 +10,13 @@
 #include "common.h"
 
 /*
- * Regular expressions: if the operating system has p_regcomp_l,
- * use it so that we can override the locale environment variable.
- * Otherwise, use our bundled PCRE implementation.
+ * Regular expressions: if we were asked to use PCRE (either our
+ * bundled version or a system version) then use their regcomp
+ * compatible implementation.
  */
 
-#ifdef GIT_USE_REGCOMP_L
-# include <regex.h>
-# include <xlocale.h>
-
-#define P_REG_EXTENDED REG_EXTENDED
-#define P_REG_ICASE REG_ICASE
-#define P_REG_NOMATCH REG_NOMATCH
+#ifdef GIT_REGEX_PCRE
 
-#define p_regex_t regex_t
-#define p_regmatch_t regmatch_t
-
-GIT_INLINE(int) p_regcomp(p_regex_t *preg, const char *pattern, int cflags)
-{
-	return regcomp_l(preg, pattern, cflags, (locale_t) 0);
-}
-
-#define p_regerror regerror
-#define p_regexec regexec
-#define p_regfree regfree
-
-#else
 # include "pcreposix.h"
 
 # define P_REG_EXTENDED PCRE_REG_EXTENDED
@@ -48,6 +29,35 @@ GIT_INLINE(int) p_regcomp(p_regex_t *preg, const char *pattern, int cflags)
 # define p_regerror pcre_regerror
 # define p_regexec pcre_regexec
 # define p_regfree pcre_regfree
+
+/* Otherwise, use regcomp_l if available, or regcomp if not. */
+#else
+
+# include <regex.h>
+
+# define P_REG_EXTENDED REG_EXTENDED
+# define P_REG_ICASE REG_ICASE
+# define P_REG_NOMATCH REG_NOMATCH
+
+# define p_regex_t regex_t
+# define p_regmatch_t regmatch_t
+
+# define p_regerror regerror
+# define p_regexec regexec
+# define p_regfree regfree
+
+# ifdef GIT_REGEX_REGCOMP_L
+#  include <xlocale.h>
+
+GIT_INLINE(int) p_regcomp(p_regex_t *preg, const char *pattern, int cflags)
+{
+	return regcomp_l(preg, pattern, cflags, (locale_t) 0);
+}
+
+# else
+#  define p_regcomp regcomp
+# endif /* GIT_REGEX_REGCOMP_L */
+
 #endif
 
 #endif