Following the recent inquiry and David Chisnall's advice, I have created
a patch that makes libc++ work a lot smoother on Linux. It allows a
plain "clang++ -stdlib=libc++" command line to work no matter what ABI
library is used, and fixes the linking errors I encountered.

However, I have absolutely no idea what it does on other platforms.

Log Message:

    Sort out common Linux linking issues.
   
    Using libc++ on Linux was problematic because using libsupc++ didn't
pull in
    all necessary symbols, whereas linking against a dynamic ABI library
required
    the user to explicitly link against the ABI library.
   
    This patch adds a new property, LIBCXX_CXX_ABI_LINK, that can be set
to dynamic
    (the default) or static. In dynamic mode, it links against the
dynamic library,
    and substitutes its unversioned .so file with a linker script that links
    against both libc++ and the ABI library. In static mode, it uses
--whole-archive
    to force inclusion of the entire ABI library into the libc++.so.
   
    It also automatically uses libstdc++ for dynamic mode and libsupc++
for static
    mode if either was selected; the two ABI names are now synonyms.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dd36b61..213b927 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -91,9 +91,8 @@ macro(setup_abi_lib abipathvar abidefines abilibs abifiles abidirs)
   list(APPEND LIBCXX_CXX_FEATURE_FLAGS ${abidefines})
   set(${abipathvar} "${${abipathvar}}"
     CACHE STRINGS
-    "Paths to ABI include directories separate by ';'."
+    "Paths to ABI include directories separated by ';'."
     )
-  set(LIBCXX_CXX_ABI_LIBRARIES ${abilibs})
   set(LIBCXX_ABILIB_FILES ${abifiles})
   file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/include")
   foreach(_d ${abidirs})
@@ -131,6 +130,29 @@ macro(setup_abi_lib abipathvar abidefines abilibs abifiles abidirs)
     FILES_MATCHING
     PATTERN "*"
     )
+  set(LIBCXX_ABILIB_FINAL_LIBRARIES
+      "${CMAKE_INSTALL_PREFIX}/lib/libc++.so.1.0")
+  if ("${LIBCXX_CXX_ABI_LINK}" STREQUAL "static")
+    # Force linker to look for static libraries only and make it include
+    # the entire library into the result.
+    list(APPEND link_flags "-Wl,-Bstatic" "-Wl,--whole-archive")
+    foreach(abilib ${abilibs})
+      list(APPEND link_flags "-l${abilib}")
+    endforeach()
+    # Disable the previous linker flags again.
+    list(APPEND link_flags "-Wl,--no-whole-archive" "-Wl,-Bdynamic")
+  else()
+    set(LIBCXX_CXX_ABI_LIBRARIES ${abilibs})
+    foreach(abilib ${abilibs})
+      list(APPEND LIBCXX_ABILIB_FINAL_LIBRARIES "-l${abilib}")
+    endforeach()
+  endif()
+  string(REPLACE ";" " " LIBCXX_ABILIB_FINAL_LIBRARIES "${LIBCXX_ABILIB_FINAL_LIBRARIES}")
+  configure_file(libc++.ldscript lib/libc++.ldscript)
+  install(FILES "${CMAKE_BINARY_DIR}/lib/libc++.ldscript"
+    DESTINATION lib
+    RENAME libc++.so
+    )
 endmacro()
 
 if ("${LIBCXX_CXX_ABI}" STREQUAL "libstdc++" OR
@@ -139,12 +161,12 @@ if ("${LIBCXX_CXX_ABI}" STREQUAL "libstdc++" OR
     cxxabi.h bits/c++config.h bits/os_defines.h bits/cpu_defines.h
     bits/cxxabi_tweaks.h bits/cxxabi_forced.h
     )
-  if ("${LIBCXX_CXX_ABI}" STREQUAL "libstdc++")
-    set(_LIBSUPCXX_DEFINES "-DLIBSTDCXX")
-    set(_LIBSUPCXX_LIBNAME stdc++)
-  else()
+  if ("${LIBCXX_CXX_ABI_LINK}" STREQUAL "static")
     set(_LIBSUPCXX_DEFINES "")
     set(_LIBSUPCXX_LIBNAME supc++)
+  else()
+    set(_LIBSUPCXX_DEFINES "-DLIBSTDCXX")
+    set(_LIBSUPCXX_LIBNAME stdc++)
   endif()
   setup_abi_lib("LIBCXX_LIBSUPCXX_INCLUDE_PATHS"
     "-D__GLIBCXX__ ${_LIBSUPCXX_DEFINES}"
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index cec0bee..58bfa67 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -96,6 +96,6 @@ set_target_properties(cxx
   )
 
 install(TARGETS cxx
-  LIBRARY DESTINATION lib
+  LIBRARY DESTINATION lib NAMELINK_SKIP
   ARCHIVE DESTINATION lib
   )
diff --git a/libc++.ldscript b/libc++.ldscript
new file mode 100644
index 0000000..362040e
--- /dev/null
+++ b/libc++.ldscript
@@ -0,0 +1 @@
+INPUT ( ${LIBCXX_ABILIB_FINAL_LIBRARIES} )
diff --git a/www/index.html b/www/index.html
index 02470ea..7a9b94b 100644
--- a/www/index.html
+++ b/www/index.html
@@ -208,21 +208,26 @@ against it with <code>-fno-rtti</code> is supported.
   (<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev";>clang mailing list</a>).</p>
 
   <!--=====================================================================-->
-  <h2>Build on Linux using CMake and libsupc++.</h2>
+  <h2>Build on Linux using CMake.</h2>
   <!--=====================================================================-->
 
   <p>
-     You will need libstdc++ in order to provide libsupc++.
-  </p>
-  
+    When building on Linux, you need a library that provides the C++ ABI
+    routines. Your choices are libsupc++, libc++abi, and libcxxrt.
+  <p>
+
+  <!--=====================================================================-->
+  <h3>Using libsupc++.</h3>
+  <!--=====================================================================-->
+
   <p>
-     Figure out where the libsupc++ headers are on your system. On Ubuntu this
-     is <code>/usr/include/c++/&lt;version&gt;</code> and
-     <code>/usr/include/c++/&lt;version&gt;/&lt;target-triple&gt;</code>
+     You will need libstdc++ in order to provide libsupc++.
   </p>
-  
+
   <p>
-     You can also figure this out by running
+     Figure out where the libsupc++ headers are on your system. Since this
+     changes a lot between distributions and versions, the best way of doing
+     this is asking GCC. You do this by running
      <pre>
 $ echo | g++ -Wp,-v -x c++ - -fsyntax-only
 ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
@@ -241,25 +246,31 @@ End of search list.
      </pre>
 
       Note the first two entries happen to be what we are looking for. This
-      may not be correct on other platforms.
+      may not be correct on other platforms. There will usually be two
+      directories with "c++" in the path, one for platform-independent parts and
+      one for platform-dependent parts which includes the target triple. You can
+      ignore the backward directory.
   </p>
-  
+
   <p>
      We can now run CMake:
      <ul>
        <li><code>CC=clang CXX=clang++ cmake -G "Unix Makefiles"
-                -DLIBCXX_CXX_ABI=libstdc++
+                -DLIBCXX_CXX_ABI=libsupc++
+                -DLIBCXX_CXX_ABI_LINK=dynamic
                 -DLIBCXX_LIBSUPCXX_INCLUDE_PATHS="/usr/include/c++/4.7/;/usr/include/c++/4.7/x86_64-linux-gnu/"
                 -DCMAKE_BUILD_TYPE=Release
                 -DCMAKE_INSTALL_PREFIX=/usr
                 &lt;libc++-source-dir&gt;</code></li>
-       <li>You can also substitute <code>-DLIBCXX_CXX_ABI=libsupc++</code>
-       above, which will cause the library to be linked to libsupc++ instead
-       of libstdc++, but this is only recommended if you know that you will
-       never need to link against libstdc++ in the same executable as libc++.
-       GCC ships libsupc++ separately but only as a static library.  If a
-       program also needs to link against libstdc++, it will provide its
-       own copy of libsupc++ and this can lead to subtle problems.
+       <li>The install prefix should be the same as for your Clang installation,
+       as Clang looks for the libc++ headers relative to its own location.</li>
+       <li>You can also substitute <code>-DLIBCXX_CXX_ABI_LINK=static</code>
+       above, which will cause the library to be linked statically to libsupc++
+       instead of dynamically to libstdc++, but this is only recommended if you
+       know that you will never need to link against libstdc++ in the same
+       executable as libc++. GCC ships libsupc++ separately but only as a static
+       library.  If a program also needs to link against libstdc++, it will
+       provide its own copy of libsupc++ and this can lead to subtle problems.
        <li><code>make</code></li>
        <li><code>sudo make install</code></li>
      </ul>
@@ -269,7 +280,7 @@ End of search list.
   </p>
 
   <!--=====================================================================-->
-  <h2>Build on Linux using CMake and libc++abi.</h2>
+  <h3>Using libc++abi.</h3>
   <!--=====================================================================-->
 
   <p>
@@ -283,37 +294,30 @@ End of search list.
      <ul>
        <li><code>CC=clang CXX=clang++ cmake -G "Unix Makefiles"
                 -DLIBCXX_CXX_ABI=libcxxabi
+                -DLIBCXX_CXX_ABI_LINK=dynamic
                 -DLIBCXX_LIBCXXABI_INCLUDE_PATHS="&lt;libc++abi-source-dir&gt;/include"
                 -DCMAKE_BUILD_TYPE=Release
                 -DCMAKE_INSTALL_PREFIX=/usr
                 &lt;libc++-source-dir&gt;</code></li>
+       <li>The install prefix should be the same as for your Clang installation,
+       as Clang looks for the libc++ headers relative to its own location.</li>
        <li><code>make</code></li>
        <li><code>sudo make install</code></li>
      </ul>
      <p>
-        Unfortunately you can't simply run clang with "-stdlib=libc++" at this point, as
-        clang is set up to link for libc++ linked to libsupc++.  To get around this
-        you'll have to set up your linker yourself (or patch clang).  For example,
-        <ul>
-          <li><code>clang++ -stdlib=libc++ helloworld.cpp -nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc</code></li>
-        </ul>
-        Alternately, you could just add libc++abi to your libraries list, which in most
-        situations will give the same result:
-        <ul>
-          <li><code>clang++ -stdlib=libc++ helloworld.cpp -lc++abi</code></li>
-        </ul>
+        You can now run clang with -stdlib=libc++.
      </p>
   </p>
 
   <!--=====================================================================-->
-  <h2>Build on Linux using CMake and libcxxrt.</h2>
+  <h3>Using libcxxrt.</h3>
   <!--=====================================================================-->
 
   <p>
      You will need to keep the source tree of
      <a href="https://github.com/pathscale/libcxxrt/";>libcxxrt</a> available
-     on your build machine and your copy of the libcxxrt shared library must
-     be placed where your linker will find it.
+     on your build machine and your copy of the libcxxrt shared or static
+     (see below) library must be placed where your linker will find it.
   </p>
  
   <p>
@@ -321,25 +325,23 @@ End of search list.
      <ul>
        <li><code>CC=clang CXX=clang++ cmake -G "Unix Makefiles"
                 -DLIBCXX_CXX_ABI=libcxxrt
+                -DLIBCXX_CXX_ABI_LINK=dynamic
                 -DLIBCXX_LIBCXXRT_INCLUDE_PATHS="&lt;libcxxrt-source-dir&gt;/src"
                 -DCMAKE_BUILD_TYPE=Release
                 -DCMAKE_INSTALL_PREFIX=/usr
                 &lt;libc++-source-dir&gt;</code></li>
+       <li>The install prefix should be the same as for your Clang installation,
+       as Clang looks for the libc++ headers relative to its own location.</li>
+       <li>The default method needs the shared version of libcxxrt. You can also
+       substitute <code>-DLIBCXX_CXX_ABI_LINK=static</code> to link against the
+       static version instead; however, this requires the static library to be
+       built as position-independent code, which it is not if you use their
+       build system without changes.</li>
        <li><code>make</code></li>
        <li><code>sudo make install</code></li>
      </ul>
      <p>
-        Unfortunately you can't simply run clang with "-stdlib=libc++" at this point, as
-        clang is set up to link for libc++ linked to libsupc++.  To get around this
-        you'll have to set up your linker yourself (or patch clang).  For example,
-        <ul>
-          <li><code>clang++ -stdlib=libc++ helloworld.cpp -nodefaultlibs -lc++ -lcxxrt -lm -lc -lgcc_s -lgcc</code></li>
-        </ul>
-        Alternately, you could just add libcxxrt to your libraries list, which in most
-        situations will give the same result:
-        <ul>
-          <li><code>clang++ -stdlib=libc++ helloworld.cpp -lcxxrt</code></li>
-        </ul>
+        You can now run clang with -stdlib=libc++.
      </p>
   </p>
 
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to