[libc++][CMake] Refactor how we link against system libraries

Summary:
Instead of populating the global LIBCXX_LIBRARIES, we use the link-time
dependency management built into CMake to propagate link flags. This
leads to a cleaner and easier-to-follow build.

Reviewers: phosek, smeenai, EricWF

Subscribers: mgorny, christof, jkorous, dexonsmith, jfb, mstorsjo, libcxx-commits

Tags: #libc

Differential Revision: https://reviews.llvm.org/D60969

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@359571 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt
index 11e3f99..906ffa4 100644
--- a/benchmarks/CMakeLists.txt
+++ b/benchmarks/CMakeLists.txt
@@ -137,7 +137,6 @@
   add_executable(${libcxx_target} EXCLUDE_FROM_ALL ${source_file})
   add_dependencies(${libcxx_target} cxx cxx-headers google-benchmark-libcxx)
   add_dependencies(cxx-benchmarks ${libcxx_target})
-  target_link_libraries(${libcxx_target} ${LIBCXX_LIBRARIES})
   if (LIBCXX_ENABLE_SHARED)
     target_link_libraries(${libcxx_target} cxx_shared)
   else()
diff --git a/cmake/Modules/HandleLibcxxFlags.cmake b/cmake/Modules/HandleLibcxxFlags.cmake
index cde2c29..b0fb98b 100644
--- a/cmake/Modules/HandleLibcxxFlags.cmake
+++ b/cmake/Modules/HandleLibcxxFlags.cmake
@@ -220,3 +220,27 @@
 macro(split_list listname)
   string(REPLACE ";" " " ${listname} "${${listname}}")
 endmacro()
+
+# For each specified flag, add that link flag to the provided target.
+# The flags are added with the given visibility, i.e. PUBLIC|PRIVATE|INTERFACE.
+function(target_add_link_flags_if_supported target visibility)
+  foreach(flag ${ARGN})
+    mangle_name("${flag}" flagname)
+    check_cxx_compiler_flag("${flag}" "LIBCXX_SUPPORTS_${flagname}_FLAG")
+    if (LIBCXX_SUPPORTS_${flagname}_FLAG)
+      target_link_libraries(${target} ${visibility} ${flag})
+    endif()
+  endforeach()
+endfunction()
+
+# For each specified flag, add that compile flag to the provided target.
+# The flags are added with the given visibility, i.e. PUBLIC|PRIVATE|INTERFACE.
+function(target_add_compile_flags_if_supported target visibility)
+  foreach(flag ${ARGN})
+    mangle_name("${flag}" flagname)
+    check_cxx_compiler_flag("${flag}" "LIBCXX_SUPPORTS_${flagname}_FLAG")
+    if (LIBCXX_SUPPORTS_${flagname}_FLAG)
+      target_compile_options(${target} ${visibility} ${flag})
+    endif()
+  endforeach()
+endfunction()
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 0564ee6..410912f 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -76,40 +76,60 @@
   endif()
 endif()
 
-# Generate private library list.
-add_library_flags_if(LIBCXX_HAS_PTHREAD_LIB pthread)
-add_library_flags_if(LIBCXX_HAS_C_LIB c)
-add_library_flags_if(LIBCXX_HAS_M_LIB m)
-add_library_flags_if(LIBCXX_HAS_RT_LIB rt)
-if (LIBCXX_USE_COMPILER_RT)
-  find_compiler_rt_library(builtins LIBCXX_BUILTINS_LIBRARY)
-  add_library_flags_if(LIBCXX_BUILTINS_LIBRARY "${LIBCXX_BUILTINS_LIBRARY}")
-else()
-  add_library_flags_if(LIBCXX_HAS_GCC_S_LIB gcc_s)
-endif()
-add_library_flags_if(LIBCXX_HAVE_CXX_ATOMICS_WITH_LIB atomic)
-add_library_flags_if(MINGW "${MINGW_LIBRARIES}")
+function(cxx_link_system_libraries target)
+  target_add_link_flags_if_supported(${target} PRIVATE "-nodefaultlibs")
+  target_add_compile_flags_if_supported(${target} PRIVATE "/Zl")
+  target_add_link_flags_if_supported(${target} PRIVATE "/nodefaultlib")
 
-# Setup flags.
-add_link_flags_if_supported(-nodefaultlibs)
-
-if (LIBCXX_TARGETING_MSVC)
-  if (LIBCXX_DEBUG_BUILD)
-    set(LIB_SUFFIX "d")
-  else()
-    set(LIB_SUFFIX "")
+  if (LIBCXX_HAS_PTHREAD_LIB)
+    target_link_libraries(${target} PUBLIC pthread)
   endif()
-  add_compile_flags(/Zl)
-  add_link_flags(/nodefaultlib)
 
-  add_library_flags(ucrt${LIB_SUFFIX}) # Universal C runtime
-  add_library_flags(vcruntime${LIB_SUFFIX}) # C++ runtime
-  add_library_flags(msvcrt${LIB_SUFFIX}) # C runtime startup files
-  add_library_flags(msvcprt${LIB_SUFFIX}) # C++ standard library. Required for exception_ptr internals.
-  # Required for standards-complaint wide character formatting functions
-  # (e.g. `printfw`/`scanfw`)
-  add_library_flags(iso_stdio_wide_specifiers)
-endif()
+  if (LIBCXX_HAS_C_LIB)
+    target_link_libraries(${target} PUBLIC c)
+  endif()
+
+  if (LIBCXX_HAS_M_LIB)
+    target_link_libraries(${target} PUBLIC m)
+  endif()
+
+  if (LIBCXX_HAS_RT_LIB)
+    target_link_libraries(${target} PUBLIC rt)
+  endif()
+
+  if (LIBCXX_USE_COMPILER_RT)
+    find_compiler_rt_library(builtins LIBCXX_BUILTINS_LIBRARY)
+    if (LIBCXX_BUILTINS_LIBRARY)
+      target_link_libraries(${target} PUBLIC "${LIBCXX_BUILTINS_LIBRARY}")
+    endif()
+  elseif (LIBCXX_HAS_GCC_S_LIB)
+    target_link_libraries(${target} PUBLIC gcc_s)
+  endif()
+
+  if (LIBCXX_HAVE_CXX_ATOMICS_WITH_LIB)
+    target_link_libraries(${target} PUBLIC atomic)
+  endif()
+
+  if (MINGW)
+    target_link_libraries(${target} PUBLIC "${MINGW_LIBRARIES}")
+  endif()
+
+  if (LIBCXX_TARGETING_MSVC)
+    if (LIBCXX_DEBUG_BUILD)
+      set(LIB_SUFFIX "d")
+    else()
+      set(LIB_SUFFIX "")
+    endif()
+
+    target_link_libraries(${target} PUBLIC ucrt${LIB_SUFFIX}) # Universal C runtime
+    target_link_libraries(${target} PUBLIC vcruntime${LIB_SUFFIX}) # C++ runtime
+    target_link_libraries(${target} PUBLIC msvcrt${LIB_SUFFIX}) # C runtime startup files
+    target_link_libraries(${target} PUBLIC msvcprt${LIB_SUFFIX}) # C++ standard library. Required for exception_ptr internals.
+    # Required for standards-complaint wide character formatting functions
+    # (e.g. `printfw`/`scanfw`)
+    target_link_libraries(${target} PUBLIC iso_stdio_wide_specifiers)
+  endif()
+endfunction()
 
 function(cxx_set_common_defines name)
   if(LIBCXX_CXX_ABI_HEADER_TARGET)
@@ -148,6 +168,7 @@
   if(COMMAND llvm_setup_rpath)
     llvm_setup_rpath(cxx_shared)
   endif()
+  cxx_link_system_libraries(cxx_shared)
   target_link_libraries(cxx_shared PRIVATE ${LIBCXX_LIBRARIES})
   set_target_properties(cxx_shared
     PROPERTIES
@@ -163,7 +184,7 @@
   # Link against LLVM libunwind
   if (LIBCXXABI_USE_LLVM_UNWINDER)
     if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND))
-      target_link_libraries(cxx_shared PRIVATE unwind_shared)
+      target_link_libraries(cxx_shared PUBLIC unwind_shared)
       list(APPEND LIBCXX_INTERFACE_LIBRARIES unwind_shared) # For the linker script
     elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND))
       # libunwind is already included in libc++abi
@@ -181,9 +202,8 @@
       target_link_libraries(cxx_shared PRIVATE "-Wl,--whole-archive,-Bstatic" "${LIBCXX_CXX_STATIC_ABI_LIBRARY}" "-Wl,-Bdynamic,--no-whole-archive")
     endif()
   else()
-    target_link_libraries(cxx_shared PRIVATE "${LIBCXX_CXX_SHARED_ABI_LIBRARY}")
+    target_link_libraries(cxx_shared PUBLIC "${LIBCXX_CXX_SHARED_ABI_LIBRARY}")
     list(APPEND LIBCXX_INTERFACE_LIBRARIES "${LIBCXX_CXX_SHARED_ABI_LIBRARY}") # For the linker script
-    list(APPEND LIBCXX_LIBRARIES "${LIBCXX_CXX_SHARED_ABI_LIBRARY}") # For the benchmarks
   endif()
 
   # Maybe re-export symbols from libc++abi
@@ -253,6 +273,7 @@
 # Build the static library.
 if (LIBCXX_ENABLE_STATIC)
   add_library(cxx_static STATIC ${exclude_from_all} ${LIBCXX_SOURCES} ${LIBCXX_HEADERS})
+  cxx_link_system_libraries(cxx_static)
   target_link_libraries(cxx_static PRIVATE ${LIBCXX_LIBRARIES})
   set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
   set_target_properties(cxx_static
@@ -388,8 +409,3 @@
                       -P "${LIBCXX_BINARY_DIR}/cmake_install.cmake")
     add_custom_target(install-libcxx DEPENDS install-cxx)
 endif()
-
-# TODO: This is needed by cxx-benchmarks but this variable isn't
-# available outside of the scope of this file so we need to export
-# it. This is not necessarily the cleanest solution.
-set(LIBCXX_LIBRARIES ${LIBCXX_LIBRARIES} PARENT_SCOPE)