EricWF created this revision.
EricWF added reviewers: mclow.lists, danalbert, jroelofs.
EricWF added a subscriber: cfe-commits.

Hi all,

This patch is a successor to D11963. However it has changed dramatically and I 
felt it would be best to start a new review thread.

Please read the design documentation added in this patch for a description of 
how it works.

http://reviews.llvm.org/D13407

Files:
  CMakeLists.txt
  cmake/Modules/HandleLibcxxFlags.cmake
  docs/DesignDocs/SupportingCustomConfigurations.rst
  docs/index.rst
  include/CMakeLists.txt
  include/__config_site.in
  test/CMakeLists.txt
  test/libcxx/test/config.py
  test/lit.site.cfg.in

Index: test/lit.site.cfg.in
===================================================================
--- test/lit.site.cfg.in
+++ test/lit.site.cfg.in
@@ -7,12 +7,6 @@
 config.enable_rtti              = "@LIBCXX_ENABLE_RTTI@"
 config.enable_shared            = "@LIBCXX_ENABLE_SHARED@"
 config.enable_32bit             = "@LIBCXX_BUILD_32_BITS@"
-config.enable_global_filesystem_namespace = "@LIBCXX_ENABLE_GLOBAL_FILESYSTEM_NAMESPACE@"
-config.enable_stdin             = "@LIBCXX_ENABLE_STDIN@"
-config.enable_stdout            = "@LIBCXX_ENABLE_STDOUT@"
-config.enable_threads           = "@LIBCXX_ENABLE_THREADS@"
-config.enable_thread_unsafe_c_functions = "@LIBCXX_ENABLE_THREAD_UNSAFE_C_FUNCTIONS@"
-config.enable_monotonic_clock   = "@LIBCXX_ENABLE_MONOTONIC_CLOCK@"
 config.cxx_abi                  = "@LIBCXX_CXX_ABI_LIBNAME@"
 config.use_sanitizer            = "@LLVM_USE_SANITIZER@"
 config.sanitizer_library        = "@LIBCXX_SANITIZER_LIBRARY@"
Index: test/libcxx/test/config.py
===================================================================
--- test/libcxx/test/config.py
+++ test/libcxx/test/config.py
@@ -357,24 +357,10 @@
         # Configure feature flags.
         self.configure_compile_flags_exceptions()
         self.configure_compile_flags_rtti()
-        self.configure_compile_flags_no_global_filesystem_namespace()
-        self.configure_compile_flags_no_stdin()
-        self.configure_compile_flags_no_stdout()
+
         enable_32bit = self.get_lit_bool('enable_32bit', False)
         if enable_32bit:
             self.cxx.flags += ['-m32']
-        # Configure threading features.
-        enable_threads = self.get_lit_bool('enable_threads', True)
-        enable_monotonic_clock = self.get_lit_bool('enable_monotonic_clock',
-                                                   True)
-        if not enable_threads:
-            self.configure_compile_flags_no_threads()
-            if not enable_monotonic_clock:
-                self.configure_compile_flags_no_monotonic_clock()
-        elif not enable_monotonic_clock:
-            self.lit_config.fatal('enable_monotonic_clock cannot be false when'
-                                  ' enable_threads is true.')
-        self.configure_compile_flags_no_thread_unsafe_c_functions()
 
         # Use verbose output for better errors
         self.cxx.flags += ['-v']
@@ -391,13 +377,46 @@
         support_path = os.path.join(self.libcxx_src_root, 'test/support')
         self.cxx.compile_flags += ['-I' + support_path]
         self.cxx.compile_flags += ['-include', os.path.join(support_path, 'nasty_macros.hpp')]
+
+        # Check for the presence of a __config_site header in the build directory
+        # If one exists we need to manually include in all of the tests.
+        config_site_header = os.path.join(self.libcxx_obj_root, '__config_site')
+        if os.path.isfile(config_site_header):
+            self.lit_config.note('Using __config_site header in %s' %
+                os.path.dirname(config_site_header))
+            # FIXME: deduce_config_site_features wont work after we add
+            # -include <header> below.
+            self.deduce_config_site_features(config_site_header)
+            self.cxx.compile_flags += ['-include', config_site_header]
+
         libcxx_headers = self.get_lit_conf(
             'libcxx_headers', os.path.join(self.libcxx_src_root, 'include'))
+
         if not os.path.isdir(libcxx_headers):
             self.lit_config.fatal("libcxx_headers='%s' is not a directory."
                                   % libcxx_headers)
         self.cxx.compile_flags += ['-I' + libcxx_headers]
 
+    def deduce_config_site_features(self, header):
+        """ deduce_config_site_features - Deduce and add the test features that
+            that are implied by the #define's in the __config_site header.
+        """
+        predefines = self.cxx.dumpMacros()
+        macros = self.cxx.dumpMacros(header)
+        feature_macros = set(macros.keys()) - set(predefines.keys())
+        # We expect the header guard to be one of the definitions
+        assert '_LIBCPP_CONFIG_SITE' in feature_macros
+        feature_macros.remove('_LIBCPP_CONFIG_SITE')
+        # The __config_site header should be non-empty. Otherwise it should
+        # have never been emitted by CMake.
+        assert len(feature_macros) > 0
+        # Transform each macro name into the feature name used in the tests.
+        # Ex. _LIBCPP_HAS_NO_THREADS -> libcpp-has-no-threads
+        for m in feature_macros:
+            assert m.startswith('_LIBCPP_HAS')
+            m = m.lower()[1:].replace('_', '-')
+            self.config.available_features.add(m)
+
     def configure_compile_flags_exceptions(self):
         enable_exceptions = self.get_lit_bool('enable_exceptions', True)
         if not enable_exceptions:
@@ -410,43 +429,7 @@
             self.config.available_features.add('libcpp-no-rtti')
             self.cxx.compile_flags += ['-fno-rtti', '-D_LIBCPP_NO_RTTI']
 
-    def configure_compile_flags_no_global_filesystem_namespace(self):
-        enable_global_filesystem_namespace = self.get_lit_bool(
-            'enable_global_filesystem_namespace', True)
-        if not enable_global_filesystem_namespace:
-            self.config.available_features.add(
-                'libcpp-has-no-global-filesystem-namespace')
-            self.cxx.compile_flags += [
-                '-D_LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE']
-
-    def configure_compile_flags_no_stdin(self):
-        enable_stdin = self.get_lit_bool('enable_stdin', True)
-        if not enable_stdin:
-            self.config.available_features.add('libcpp-has-no-stdin')
-            self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_STDIN']
-
-    def configure_compile_flags_no_stdout(self):
-        enable_stdout = self.get_lit_bool('enable_stdout', True)
-        if not enable_stdout:
-            self.config.available_features.add('libcpp-has-no-stdout')
-            self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_STDOUT']
-
-    def configure_compile_flags_no_threads(self):
-        self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_THREADS']
-        self.config.available_features.add('libcpp-has-no-threads')
-
-    def configure_compile_flags_no_thread_unsafe_c_functions(self):
-        enable_thread_unsafe_c_functions = self.get_lit_bool(
-            'enable_thread_unsafe_c_functions', True)
-        if not enable_thread_unsafe_c_functions:
-            self.cxx.compile_flags += [
-                '-D_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS']
-            self.config.available_features.add(
-                'libcpp-has-no-thread-unsafe-c-functions')
 
-    def configure_compile_flags_no_monotonic_clock(self):
-        self.cxx.compile_flags += ['-D_LIBCPP_HAS_NO_MONOTONIC_CLOCK']
-        self.config.available_features.add('libcpp-has-no-monotonic-clock')
 
     def configure_link_flags(self):
         no_default_flags = self.get_lit_bool('no_default_flags', False)
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -25,6 +25,7 @@
 # The tests shouldn't link to any ABI library when it has been linked into
 # libc++ statically.
 if (LIBCXX_ENABLE_STATIC_ABI_LIBRARY)
+   message(FATAL_ERROR "SHIT")
   set(LIBCXX_CXX_ABI_LIBNAME "none")
 endif()
 set(LIBCXX_TARGET_INFO "libcxx.test.target_info.LocalTI" CACHE STRING
Index: include/__config_site.in
===================================================================
--- /dev/null
+++ include/__config_site.in
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_CONFIG_SITE
+#define _LIBCPP_CONFIG_SITE
+
+#cmakedefine _LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE
+#cmakedefine _LIBCPP_HAS_NO_STDIN
+#cmakedefine _LIBCPP_HAS_NO_STDOUT
+#cmakedefine _LIBCPP_HAS_NO_THREADS
+#cmakedefine _LIBCPP_HAS_NO_MONOTONIC_CLOCK
+#cmakedefine _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS
+
+#endif
Index: include/CMakeLists.txt
===================================================================
--- include/CMakeLists.txt
+++ include/CMakeLists.txt
@@ -1,19 +1,23 @@
 if (NOT LIBCXX_INSTALL_SUPPORT_HEADERS)
   set(LIBCXX_SUPPORT_HEADER_PATTERN PATTERN "support" EXCLUDE)
 endif()
+
+
 set(LIBCXX_HEADER_PATTERN
   PATTERN "*"
   PATTERN "CMakeLists.txt" EXCLUDE
   PATTERN ".svn" EXCLUDE
+  PATTERN "__config_site.in" EXCLUDE
   ${LIBCXX_SUPPORT_HEADER_PATTERN}
   )
 
 file(COPY .
-  DESTINATION "${CMAKE_BINARY_DIR}/include/c++/v1"
+  DESTINATION include/c++/v1
   FILES_MATCHING
   ${LIBCXX_HEADER_PATTERN}
   )
 
+
 if (LIBCXX_INSTALL_HEADERS)
   install(DIRECTORY .
     DESTINATION include/c++/v1
@@ -22,4 +26,25 @@
     ${LIBCXX_HEADER_PATTERN}
     PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
   )
+
+  if (LIBCXX_NEEDS_SITE_CONFIG)
+    # Generate and install a custom __config header. The new header is created
+    # by  prepending __config_site to the current __config header.
+    # TODO(EricWF) Is it portable to use "cat" and ">>"?
+    add_custom_command(OUTPUT ${LIBCXX_BINARY_DIR}/__generated_config
+      COMMAND ${CMAKE_COMMAND} -E copy ${LIBCXX_BINARY_DIR}/__config_site ${LIBCXX_BINARY_DIR}/__generated_config
+      COMMAND cat ${LIBCXX_SOURCE_DIR}/include/__config >> ${LIBCXX_BINARY_DIR}/__generated_config
+      DEPENDS ${LIBCXX_SOURCE_DIR}/include/__config
+    )
+    # Add a target that executes the generation commands.
+    add_custom_target(generate_config_header ALL
+      DEPENDS ${LIBCXX_BINARY_DIR}/__generated_config)
+    # Install the generated header as __config.
+    install(FILES ${LIBCXX_BINARY_DIR}/__generated_config
+      DESTINATION include/c++/v1
+      PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
+      RENAME __config
+      COMPONENT libcxx)
+  endif()
+
 endif()
Index: docs/index.rst
===================================================================
--- docs/index.rst
+++ docs/index.rst
@@ -124,6 +124,12 @@
 Design Documents
 ----------------
 
+.. toctree::
+   :maxdepth: 1
+
+   DesignDocs/SupportingCustomConfigurations
+
+
 * `<atomic> design <http://libcxx.llvm.org/atomic_design.html>`_
 * `<type_traits> design <http://libcxx.llvm.org/type_traits_design.html>`_
 * `Status of debug mode <http://libcxx.llvm.org/debug_mode.html>`_
Index: docs/DesignDocs/SupportingCustomConfigurations.rst
===================================================================
--- /dev/null
+++ docs/DesignDocs/SupportingCustomConfigurations.rst
@@ -0,0 +1,90 @@
+=============================================================
+Capturing configuration information during installation
+========================================================
+
+
+.. contents::
+   :local:
+
+The Problem
+===========
+
+Currently the libc++ supports building the library with a number of different
+configuration options.  Unfortunately all of that configuration information is
+lost when libc++ is installed. In order to support "persistent"
+configurations libc++ needs a mechanism to capture the configuration options
+in the INSTALLED headers.
+
+
+Design Goals
+============
+
+* The solution should not INSTALL any additional headers. We don't want an extra
+  #include slowing everybody down.
+
+* The solution should not unduly affect libc++ developers. The problem is limited
+  to installed versions of libc++ and the solution should be as well.
+
+* The solution should not modify any existing headers EXCEPT during installation.
+  It makes developers lives harder if they have to regenerate the libc++ headers
+  every time they are modified.
+
+* The solution should not make any of the libc++ headers dependant on
+  files generated by the build system. The headers should be able to compile
+  out of the box without any modification.
+
+* The solution should not have ANY effect on users who don't need special
+  configuration options. The vast majority of users will never need this so it
+  shouldn't cost them.
+
+
+The Solution
+============
+
+When you first configure libc++ using CMake we check to see if we need to
+capture any options. If we haven't been given any "persistent" options then
+we do NOTHING.
+
+Otherwise we create a custom installation rule that modifies the installed __config
+header. The rule first generates a dummy "__config_site" header containing the required
+#defines. The contents of the dummy header are then prependend to the installed
+__config header. By manually prepending the files we avoid the cost of an
+extra #include and we allow the __config header to be ignorant of the extra
+ configuration all together. An example "__config" header generated when
+-DLIBCXX_ENABLE_THREADS=OFF is given to CMake would look something like:
+
+.. code-block:: cpp
+
+  //===----------------------------------------------------------------------===//
+  //
+  //                     The LLVM Compiler Infrastructure
+  //
+  // This file is dual licensed under the MIT and the University of Illinois Open
+  // Source Licenses. See LICENSE.TXT for details.
+  //
+  //===----------------------------------------------------------------------===//
+
+  #ifndef _LIBCPP_CONFIG_SITE
+  #define _LIBCPP_CONFIG_SITE
+
+  /* #undef _LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE */
+  /* #undef _LIBCPP_HAS_NO_STDIN */
+  /* #undef _LIBCPP_HAS_NO_STDOUT */
+  #define _LIBCPP_HAS_NO_THREADS
+  /* #undef _LIBCPP_HAS_NO_MONOTONIC_CLOCK */
+  /* #undef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS */
+
+  #endif
+  // -*- C++ -*-
+  //===--------------------------- __config ---------------------------------===//
+  //
+  //                     The LLVM Compiler Infrastructure
+  //
+  // This file is dual licensed under the MIT and the University of Illinois Open
+  // Source Licenses. See LICENSE.TXT for details.
+  //
+  //===----------------------------------------------------------------------===//
+
+  #ifndef _LIBCPP_CONFIG
+  #define _LIBCPP_CONFIG
+
Index: cmake/Modules/HandleLibcxxFlags.cmake
===================================================================
--- cmake/Modules/HandleLibcxxFlags.cmake
+++ cmake/Modules/HandleLibcxxFlags.cmake
@@ -49,6 +49,20 @@
   endif()
 endmacro()
 
+macro(config_define_if condition def)
+  if (${condition})
+    set(${def} ON)
+    set(LIBCXX_NEEDS_SITE_CONFIG ON)
+  endif()
+endmacro()
+
+macro(config_define_if_not condition def)
+  if (NOT ${condition})
+    set(${def} ON)
+    set(LIBCXX_NEEDS_SITE_CONFIG ON)
+  endif()
+endmacro()
+
 # Add a specified list of flags to both 'LIBCXX_COMPILE_FLAGS' and
 # 'LIBCXX_LINK_FLAGS'.
 macro(add_flags)
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -170,6 +170,7 @@
 set(LIBCXX_LINK_FLAGS "")
 set(LIBCXX_LIBRARIES "")
 
+
 # Configure compiler.
 include(config-ix)
 
@@ -258,16 +259,8 @@
 
 # Feature flags ===============================================================
 define_if(MSVC -D_CRT_SECURE_NO_WARNINGS)
-define_if_not(LIBCXX_ENABLE_GLOBAL_FILESYSTEM_NAMESPACE -D_LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE)
-define_if_not(LIBCXX_ENABLE_STDIN -D_LIBCPP_HAS_NO_STDIN)
-define_if_not(LIBCXX_ENABLE_STDOUT -D_LIBCPP_HAS_NO_STDOUT)
-define_if_not(LIBCXX_ENABLE_THREADS -D_LIBCPP_HAS_NO_THREADS)
-define_if_not(LIBCXX_ENABLE_MONOTONIC_CLOCK -D_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
-define_if_not(LIBCXX_ENABLE_THREAD_UNSAFE_C_FUNCTIONS -D_LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS)
-
-
-# Sanitizer flags =============================================================
 
+# Sanitizer flags ==============================================================
 # Configure for sanitizers. If LIBCXX_BUILT_STANDALONE then we have to do
 # the flag translation ourselves. Othewise LLVM's CMakeList.txt will handle it.
 if (LIBCXX_BUILT_STANDALONE)
@@ -301,6 +294,25 @@
     message(WARNING "LLVM_USE_SANITIZER is not supported on this platform.")
   endif()
 endif()
+
+
+# Configuration file flags =====================================================
+config_define_if_not(LIBCXX_ENABLE_GLOBAL_FILESYSTEM_NAMESPACE _LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE)
+config_define_if_not(LIBCXX_ENABLE_STDIN _LIBCPP_HAS_NO_STDIN)
+config_define_if_not(LIBCXX_ENABLE_STDOUT _LIBCPP_HAS_NO_STDOUT)
+config_define_if_not(LIBCXX_ENABLE_THREADS _LIBCPP_HAS_NO_THREADS)
+config_define_if_not(LIBCXX_ENABLE_MONOTONIC_CLOCK _LIBCPP_HAS_NO_MONOTONIC_CLOCK)
+config_define_if_not(LIBCXX_ENABLE_THREAD_UNSAFE_C_FUNCTIONS _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS)
+
+if (LIBCXX_NEEDS_SITE_CONFIG)
+  set(CS_HEADER ${LIBCXX_BINARY_DIR}/__config_site)
+  configure_file(
+    include/__config_site.in
+    ${CS_HEADER}
+    @ONLY)
+  add_compile_flags(-include ${CS_HEADER})
+endif()
+
 #===============================================================================
 # Setup Source Code And Tests
 #===============================================================================
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to