Make the serf.def file a proper target in the CMake build, so that it gets
regenerated during the build if any of the public headers change.

* CMakeLists.txt: Use the current source directory everywhere to keep
   references localised for external scripts. Add a custom target for
   generating the serf.def file.

* build/SerfWindowsGenDef.cmake: New script, generates the .def file.
* build/SerfWindowsGenDef.cmake: Make the regular expressions more readable.

git-svn-id: https://svn.apache.org/repos/asf/serf/trunk@1835100 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d54f15d..632f69e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,7 +18,7 @@
 
 cmake_minimum_required(VERSION 3.0.2)
 
-list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/build")
+list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/build")
 include(SerfVersion)
 
 project("Serf" VERSION ${SERF_VERSION} LANGUAGES C)
@@ -57,14 +57,22 @@
 
 
 # Public headers
-set(HEADERS
+list(APPEND HEADERS
     "serf.h"
     "serf_bucket_types.h"
     "serf_bucket_util.h"
 )
 
+# List of symbols that should not be exported from the shared library.
+list(APPEND EXPORTS_BLACKLIST
+     "serf_connection_switch_protocol"
+     "serf_http_protocol_create"
+     "serf_https_protocol_create"
+     "serf_http_request_queue"
+)
+
 # Serf library source files
-set(SOURCES
+list(APPEND SOURCES
     "src/config_store.c"
     "src/context.c"
     "src/deprecated.c"
@@ -115,14 +123,21 @@
 )
 
 if(SERF_WINDOWS)
-  list(APPEND EXPORTS_BLACKLIST
-       "serf_connection_switch_protocol"
-       "serf_http_protocol_create"
-       "serf_https_protocol_create"
-       "serf_http_request_queue"
+  # Generate the .def file for the Windows DLL import library.
+  set(SERF_DEF_FILE "${CMAKE_CURRENT_BINARY_DIR}/serf.def")
+  add_custom_command(
+    OUTPUT "${SERF_DEF_FILE}"
+    DEPENDS ${HEADERS}
+    COMMAND ${CMAKE_COMMAND}
+            -DCMAKE_SYSTEM_NAME="${CMAKE_SYSTEM_NAME}"
+            -DCMAKE_MODULE_PATH="${CMAKE_MODULE_PATH}"
+            -DSERF_DEF_BLACKLIST="${EXPORTS_BLACKLIST}"
+            -DSERF_DEF_HEADERS="${HEADERS}"
+            -DSERF_DEF_FILE="${SERF_DEF_FILE}"
+            -P "build/SerfWindowsGenDef.cmake"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
   )
-  SerfWindowsGenDef("${EXPORTS_BLACKLIST}" "${CMAKE_BINARY_DIR}/serf.def" ${HEADERS})
-  set(SHARED_SOURCES "serf.rc" "${CMAKE_BINARY_DIR}/serf.def")
+  set(SHARED_SOURCES "serf.rc" "${SERF_DEF_FILE}")
 
   # Static OpenSSL, APR and APR-Util need additional libraries that are not
   # linked by default by CMake. These will be ignored by the linker if they're
@@ -205,7 +220,7 @@
 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${APR_CFLAGS}")
 
 include_directories(BEFORE SYSTEM ${DEPENDENCY_INCLUDES})
-include_directories(${CMAKE_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 
 
 # Feature tests
diff --git a/build/SerfWindowsGenDef.cmake b/build/SerfWindowsGenDef.cmake
new file mode 100644
index 0000000..1fc07bc
--- /dev/null
+++ b/build/SerfWindowsGenDef.cmake
@@ -0,0 +1,25 @@
+#   Licensed to the Apache Software Foundation (ASF) under one
+#   or more contributor license agreements.  See the NOTICE file
+#   distributed with this work for additional information
+#   regarding copyright ownership.  The ASF licenses this file
+#   to you under the Apache License, Version 2.0 (the
+#   "License"); you may not use this file except in compliance
+#   with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing,
+#   software distributed under the License is distributed on an
+#   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#   KIND, either express or implied.  See the License for the
+#   specific language governing permissions and limitations
+#   under the License.
+# ===================================================================
+
+# Generate Serf's .def file for Windows DLLs.
+
+include(SerfWindowsToolkit)
+
+string(REGEX REPLACE " +" ";" SERF_DEF_BLACKLIST "${SERF_DEF_BLACKLIST}")
+string(REGEX REPLACE " +" ";" SERF_DEF_HEADERS "${SERF_DEF_HEADERS}")
+SerfWindowsGenDef("${SERF_DEF_BLACKLIST}" "${SERF_DEF_FILE}" ${SERF_DEF_HEADERS})
diff --git a/build/SerfWindowsToolkit.cmake b/build/SerfWindowsToolkit.cmake
index 7968024..a275e6b 100644
--- a/build/SerfWindowsToolkit.cmake
+++ b/build/SerfWindowsToolkit.cmake
@@ -37,21 +37,24 @@
 # Generate a Windows DLL .def file from a list of headers.
 function(SerfWindowsGenDef blacklist_ target_)
   if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
-    set(func_search_rx_ "^(([a-zA-Z_0-9]+|\\*) )+\\*?(serf_[a-z][a-zA-Z_0-9]*)\\(")
-    set(type_search_rx_ "^extern const serf_bucket_type_t (serf_[a-z_]*);")
-    set(func_rx_ "^(([a-zA-Z_0-9]+|\\*) )+\\*?(serf_[a-z][a-zA-Z_0-9]*).*$")
-    set(type_rx_ "^extern const serf_bucket_type_t (serf_[a-z_]*).*$")
+    set(W "[a-zA-Z_0-9]") # Word characters pattern
+    set(base_func_rx_     "^((${W}+|\\*) )+\\*?(serf_[a-z]${W}*)\\(")
+    set(base_type_rx_     "^extern const serf_bucket_type_t (serf_[a-z_]*)")
+    set(func_search_rx_   "${base_func_rx_}")
+    set(type_search_rx_   "${base_type_rx_};")
+    set(func_name_rx_     "${base_func_rx_}.*$")
+    set(type_name_rx_     "${base_type_rx_}.*$")
 
     foreach(file_ ${ARGN})
       message(STATUS "Looking for exports in ${file_}")
       file(STRINGS ${file_} funcs_ REGEX "${func_search_rx_}")
       file(STRINGS ${file_} types_ REGEX "${type_search_rx_}")
       foreach(sym_ ${funcs_})
-        string(REGEX REPLACE "${func_rx_}" "\\3" def_ ${sym_})
+        string(REGEX REPLACE "${func_name_rx_}" "\\3" def_ ${sym_})
         list(APPEND defs_ ${def_})
       endforeach()
       foreach(sym_ ${types_})
-        string(REGEX REPLACE "${type_rx_}" "\\1" def_ ${sym_})
+        string(REGEX REPLACE "${type_name_rx_}" "\\1" def_ ${sym_})
         list(APPEND defs_ ${def_})
       endforeach()
     endforeach()