pw_libc: Pull in some string functions

Change-Id: If7e63e6238d2054f3bb92c8e455368497118f941
Original-Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/137314
Original-Reviewed-by: Keir Mierle <keir@google.com>
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/llvm-integration/+/235117
Reviewed-by: Keir Mierle <keir@google.com>
Commit-Queue: Prabhu Karthikeyan Rajasekaran <prabhukr@google.com>
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
diff --git a/pw_libc/BUILD.gn b/pw_libc/BUILD.gn
index df7acd7..53ad5cd 100644
--- a/pw_libc/BUILD.gn
+++ b/pw_libc/BUILD.gn
@@ -17,6 +17,7 @@
 import("$dir_pw_build/target_types.gni")
 import("$dir_pw_docgen/docs.gni")
 import("$dir_pw_third_party/llvm_libc/llvm_libc.gni")
+import("$dir_pw_toolchain/generate_toolchain.gni")
 import("$dir_pw_unit_test/test.gni")
 
 config("default_config") {
@@ -35,6 +36,19 @@
   deps = [ "$dir_pw_containers" ]
 }
 
+# Clang has __attribute__(("no-builtin")), but gcc doesn't support it so we
+# need this flag instead.
+config("no-builtin") {
+  cflags = [ "-fno-builtin" ]
+}
+
+# Downstream projects sometimes build with -Wshadow, which on gcc also warns
+# about constructor arguments shadowing struct members. This is too pedantic
+# and not reasonable to change upstream llvm-libc.
+config("no-shadow") {
+  cflags = [ "-Wno-shadow" ]
+}
+
 # If dir_pw_third_party_llvm_libc is defined, use that directory to create a
 # pw_libc.a from llvm-libc. Otherwise, we create an empty pw_libc.a.
 if (dir_pw_third_party_llvm_libc != "") {
@@ -42,13 +56,40 @@
     functions = [ "abs" ]
   }
 
+  pw_libc_source_set("string") {
+    defines = [ "LIBC_COPT_MEMCPY_USE_EMBEDDED_TINY" ]
+    functions = [
+      "strcmp",
+      "strcpy",
+      "strstr",
+      "strnlen",
+      "memcpy",
+      "memset",
+      "memmove",
+    ]
+
+    # memmove tests use gtest matchers which pw_unit_test doesn't support.
+    no_test_functions = [ "memmove" ]
+
+    configs = [
+      ":no-builtin",
+      ":no-shadow",
+    ]
+  }
+
   pw_static_library("pw_libc") {
     complete_static_lib = true
-    deps = [ ":stdlib" ]
+    deps = [
+      ":stdlib",
+      ":string",
+    ]
   }
 
   pw_test_group("llvm_libc_tests") {
-    tests = [ ":stdlib_tests" ]
+    tests = [
+      ":stdlib_tests",
+      ":string_tests",
+    ]
   }
 } else {
   pw_static_library("pw_libc") {
diff --git a/third_party/llvm_libc/llvm_libc.gni b/third_party/llvm_libc/llvm_libc.gni
index be5f997..05f80b0 100644
--- a/third_party/llvm_libc/llvm_libc.gni
+++ b/third_party/llvm_libc/llvm_libc.gni
@@ -35,10 +35,21 @@
 
     defines = [
       "LIBC_COPT_PUBLIC_PACKAGING=1",
-      "LLVM_LIBC_FUNCTION_ATTR=[[gnu::visibility(\"default\")]]",
       "LIBC_INLINE=inline",
     ]
 
+    if (defined(invoker.defines)) {
+      defines += invoker.defines
+    }
+
+    forward_variables_from(invoker,
+                           "*",
+                           [
+                             "defines",
+                             "functions",
+                             "no_test_functions",
+                           ])
+
     public = []
     sources = []
 
@@ -54,9 +65,25 @@
     include_dirs = [ dir_pw_third_party_llvm_libc ]
     defines = [ "LIBC_COPT_TEST_USE_PIGWEED" ]
 
+    if (defined(invoker.defines)) {
+      defines += invoker.defines
+    }
+
+    forward_variables_from(invoker,
+                           "*",
+                           [
+                             "defines",
+                             "functions",
+                             "no_test_functions",
+                           ])
+
     sources = []
 
-    foreach(function, invoker.functions) {
+    no_test_functions = []
+    if (defined(invoker.no_test_functions)) {
+      no_test_functions = invoker.no_test_functions
+    }
+    foreach(function, invoker.functions - no_test_functions) {
       sources += [ "$dir/${function}_test.cpp" ]
     }