Patch pip environment with xcode sdk location. (#697)

diff --git a/docs/BUILD b/docs/BUILD
index 94a7c84..d295821 100644
--- a/docs/BUILD
+++ b/docs/BUILD
@@ -62,6 +62,7 @@
 bzl_library(
     name = "pip_install_bzl",
     srcs = [
+        "//python:bzl",
         "//python/pip_install:bzl",
     ],
     deps = [
diff --git a/docs/pip.md b/docs/pip.md
index 732d391..4853e52 100644
--- a/docs/pip.md
+++ b/docs/pip.md
@@ -5,8 +5,8 @@
 ## compile_pip_requirements
 
 <pre>
-compile_pip_requirements(<a href="#compile_pip_requirements-name">name</a>, <a href="#compile_pip_requirements-extra_args">extra_args</a>, <a href="#compile_pip_requirements-visibility">visibility</a>, <a href="#compile_pip_requirements-requirements_in">requirements_in</a>, <a href="#compile_pip_requirements-requirements_txt">requirements_txt</a>, <a href="#compile_pip_requirements-tags">tags</a>,
-                         <a href="#compile_pip_requirements-kwargs">kwargs</a>)
+compile_pip_requirements(<a href="#compile_pip_requirements-name">name</a>, <a href="#compile_pip_requirements-extra_args">extra_args</a>, <a href="#compile_pip_requirements-visibility">visibility</a>, <a href="#compile_pip_requirements-requirements_in">requirements_in</a>, <a href="#compile_pip_requirements-requirements_txt">requirements_txt</a>,
+                         <a href="#compile_pip_requirements-requirements_linux">requirements_linux</a>, <a href="#compile_pip_requirements-requirements_darwin">requirements_darwin</a>, <a href="#compile_pip_requirements-requirements_windows">requirements_windows</a>, <a href="#compile_pip_requirements-tags">tags</a>, <a href="#compile_pip_requirements-kwargs">kwargs</a>)
 </pre>
 
 Generates targets for managing pip dependencies with pip-compile.
@@ -31,6 +31,9 @@
 | visibility |  passed to both the _test and .update rules   |  <code>["//visibility:private"]</code> |
 | requirements_in |  file expressing desired dependencies   |  <code>None</code> |
 | requirements_txt |  result of "compiling" the requirements.in file   |  <code>None</code> |
+| requirements_linux |  File of linux specific resolve output to check validate if requirement.in has changes.   |  <code>None</code> |
+| requirements_darwin |  File of darwin specific resolve output to check validate if requirement.in has changes.   |  <code>None</code> |
+| requirements_windows |  File of windows specific resolve output to check validate if requirement.in has changes.   |  <code>None</code> |
 | tags |  tagging attribute common to all build rules, passed to both the _test and .update rules   |  <code>None</code> |
 | kwargs |  other bazel attributes passed to the "_test" rule   |  none |
 
diff --git a/examples/pip_install/BUILD b/examples/pip_install/BUILD
index ecc083f..ad983b2 100644
--- a/examples/pip_install/BUILD
+++ b/examples/pip_install/BUILD
@@ -62,6 +62,7 @@
 compile_pip_requirements(
     name = "requirements",
     extra_args = ["--allow-unsafe"],
+    requirements_windows = ":requirements_windows.txt",
 )
 
 # Test the use of all pip_install utilities in a single py_test
diff --git a/examples/pip_install/WORKSPACE b/examples/pip_install/WORKSPACE
index 1fabf94..0b33a2b 100644
--- a/examples/pip_install/WORKSPACE
+++ b/examples/pip_install/WORKSPACE
@@ -50,7 +50,7 @@
     # (Optional) You can set an environment in the pip process to control its
     # behavior. Note that pip is run in "isolated" mode so no PIP_<VAR>_<NAME>
     # style env vars are read, but env vars that control requests and urllib3
-    # can be passed
+    # can be passed.
     #environment = {"HTTP_PROXY": "http://my.proxy.fun/"},
 
     # Uses the default repository name "pip"
diff --git a/examples/pip_install/main.py b/examples/pip_install/main.py
index b65ad0e..4440cde 100644
--- a/examples/pip_install/main.py
+++ b/examples/pip_install/main.py
@@ -1,6 +1,5 @@
 import boto3
 
-
 def the_dir():
     return dir(boto3)
 
diff --git a/examples/pip_install/requirements.in b/examples/pip_install/requirements.in
index 2351369..11ede3c 100644
--- a/examples/pip_install/requirements.in
+++ b/examples/pip_install/requirements.in
@@ -1,3 +1,4 @@
 boto3~=1.14.51
 s3cmd~=2.1.0
 yamllint~=1.26.3
+tree-sitter==0.20.0 ; sys_platform != "win32"
diff --git a/examples/pip_install/requirements.txt b/examples/pip_install/requirements.txt
index 26de1ad..db76801 100644
--- a/examples/pip_install/requirements.txt
+++ b/examples/pip_install/requirements.txt
@@ -86,6 +86,10 @@
     --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
     --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
     # via python-dateutil
+tree-sitter==0.20.0 ; sys_platform != "win32" \
+    --hash=sha256:1940f64be1e8c9c3c0e34a2258f1e4c324207534d5b1eefc5ab2960a9d98f668 \
+    --hash=sha256:51a609a7c1bd9d9e75d92ee128c12c7852ae70a482900fbbccf3d13a79e0378c
+    # via -r requirements.in
 urllib3==1.25.11 \
     --hash=sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2 \
     --hash=sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e
diff --git a/examples/pip_install/requirements_windows.txt b/examples/pip_install/requirements_windows.txt
new file mode 100644
index 0000000..26de1ad
--- /dev/null
+++ b/examples/pip_install/requirements_windows.txt
@@ -0,0 +1,101 @@
+#
+# This file is autogenerated by pip-compile with python 3.9
+# To update, run:
+#
+#    bazel run //:requirements.update
+#
+boto3==1.14.51 \
+    --hash=sha256:a6bdb808e948bd264af135af50efb76253e85732c451fa605b7a287faf022432 \
+    --hash=sha256:f9dbccbcec916051c6588adbccae86547308ac4cd154f1eb7cf6422f0e391a71
+    # via -r requirements.in
+botocore==1.17.63 \
+    --hash=sha256:40f13f6c9c29c307a9dc5982739e537ddce55b29787b90c3447b507e3283bcd6 \
+    --hash=sha256:aa88eafc6295132f4bc606f1df32b3248e0fa611724c0a216aceda767948ac75
+    # via
+    #   boto3
+    #   s3transfer
+docutils==0.15.2 \
+    --hash=sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0 \
+    --hash=sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827 \
+    --hash=sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99
+    # via botocore
+jmespath==0.10.0 \
+    --hash=sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9 \
+    --hash=sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f
+    # via
+    #   boto3
+    #   botocore
+pathspec==0.9.0 \
+    --hash=sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a \
+    --hash=sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1
+    # via yamllint
+python-dateutil==2.8.2 \
+    --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
+    --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
+    # via
+    #   botocore
+    #   s3cmd
+python-magic==0.4.24 \
+    --hash=sha256:4fec8ee805fea30c07afccd1592c0f17977089895bdfaae5fec870a84e997626 \
+    --hash=sha256:de800df9fb50f8ec5974761054a708af6e4246b03b4bdaee993f948947b0ebcf
+    # via s3cmd
+pyyaml==6.0 \
+    --hash=sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293 \
+    --hash=sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b \
+    --hash=sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57 \
+    --hash=sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b \
+    --hash=sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4 \
+    --hash=sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07 \
+    --hash=sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba \
+    --hash=sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9 \
+    --hash=sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287 \
+    --hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \
+    --hash=sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0 \
+    --hash=sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0 \
+    --hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \
+    --hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \
+    --hash=sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2 \
+    --hash=sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc \
+    --hash=sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c \
+    --hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \
+    --hash=sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4 \
+    --hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \
+    --hash=sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34 \
+    --hash=sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b \
+    --hash=sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c \
+    --hash=sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb \
+    --hash=sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737 \
+    --hash=sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3 \
+    --hash=sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d \
+    --hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \
+    --hash=sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78 \
+    --hash=sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803 \
+    --hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \
+    --hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \
+    --hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5
+    # via yamllint
+s3cmd==2.1.0 \
+    --hash=sha256:49cd23d516b17974b22b611a95ce4d93fe326feaa07320bd1d234fed68cbccfa \
+    --hash=sha256:966b0a494a916fc3b4324de38f089c86c70ee90e8e1cae6d59102103a4c0cc03
+    # via -r requirements.in
+s3transfer==0.3.7 \
+    --hash=sha256:35627b86af8ff97e7ac27975fe0a98a312814b46c6333d8a6b889627bcd80994 \
+    --hash=sha256:efa5bd92a897b6a8d5c1383828dca3d52d0790e0756d49740563a3fb6ed03246
+    # via boto3
+six==1.16.0 \
+    --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+    --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+    # via python-dateutil
+urllib3==1.25.11 \
+    --hash=sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2 \
+    --hash=sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e
+    # via botocore
+yamllint==1.26.3 \
+    --hash=sha256:3934dcde484374596d6b52d8db412929a169f6d9e52e20f9ade5bf3523d9b96e
+    # via -r requirements.in
+
+# The following packages are considered to be unsafe in a requirements file:
+setuptools==59.6.0 \
+    --hash=sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373 \
+    --hash=sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e
+    # via yamllint
diff --git a/python/pip_install/parse_requirements_to_bzl/__init__.py b/python/pip_install/parse_requirements_to_bzl/__init__.py
index 83526a7..07ee92d 100644
--- a/python/pip_install/parse_requirements_to_bzl/__init__.py
+++ b/python/pip_install/parse_requirements_to_bzl/__init__.py
@@ -94,7 +94,7 @@
     repository rule, which will represent the individual requirements.
 
     Generates a requirements.bzl file containing a macro (install_deps()) which instantiates
-    a repository rule for each requirment in the lock file.
+    a repository rule for each requirement in the lock file.
     """
     install_req_and_lines = parse_install_requirements(
         requirements_lock, whl_library_args["extra_pip_args"]
diff --git a/python/pip_install/pip_compile.py b/python/pip_install/pip_compile.py
index e9c5cdf..aeb36de 100644
--- a/python/pip_install/pip_compile.py
+++ b/python/pip_install/pip_compile.py
@@ -6,116 +6,146 @@
 
 from piptools.scripts.compile import cli
 
-if len(sys.argv) < 4:
-    print(
-        "Expected at least two arguments: requirements_in requirements_out",
-        file=sys.stderr,
-    )
-    sys.exit(1)
 
-requirements_in = os.path.relpath(sys.argv.pop(1))
-requirements_txt = os.path.relpath(sys.argv.pop(1))
-parts = requirements_in.split(os.path.sep, 2)
-if parts[0] == "external":
-    requirements_in = parts[2]
-    requirements_txt = requirements_txt if "BUILD_WORKSPACE_DIRECTORY" in os.environ else os.path.join("..", "..", requirements_txt)
-    os.chdir(os.path.join(parts[0], parts[1]))
-update_target_label = sys.argv.pop(1)
+def _select_golden_requirements_file(
+    requirements_txt, requirements_linux, requirements_darwin, requirements_windows
+):
+    """Switch the golden requirements file, used to validate if updates are needed,
+    to a specified platform specific one.  Fallback on the platform independent one.
+    """
 
-# Before loading click, set the locale for its parser.
-# If it leaks through to the system setting, it may fail:
-# RuntimeError: Click will abort further execution because Python 3 was configured to use ASCII
-# as encoding for the environment. Consult https://click.palletsprojects.com/python3/ for
-# mitigation steps.
-os.environ["LC_ALL"] = "C.UTF-8"
-os.environ["LANG"] = "C.UTF-8"
+    plat = sys.platform
+    if plat == "linux" and requirements_linux is not None:
+        return requirements_linux
+    elif plat == "darwin" and requirements_darwin is not None:
+        return requirements_darwin
+    elif plat == "win32" and requirements_windows is not None:
+        return requirements_windows
+    else:
+        return requirements_txt
 
-UPDATE = True
-# Detect if we are running under `bazel test`
-if "TEST_TMPDIR" in os.environ:
-    UPDATE = False
-    # pip-compile wants the cache files to be writeable, but if we point
-    # to the real user cache, Bazel sandboxing makes the file read-only
-    # and we fail.
-    # In theory this makes the test more hermetic as well.
-    sys.argv.append("--cache-dir")
-    sys.argv.append(os.environ["TEST_TMPDIR"])
-    # Make a copy for pip-compile to read and mutate
-    requirements_out = os.path.join(
-        os.environ["TEST_TMPDIR"], os.path.basename(requirements_txt) + ".out"
-    )
-    copyfile(requirements_txt, requirements_out)
 
-elif "BUILD_WORKSPACE_DIRECTORY" in os.environ:
-    # This value, populated when running under `bazel run`, is a path to the
-    # "root of the workspace where the build was run."
-    # This matches up with the values passed in via the macro using the 'rootpath' Make variable,
-    # which for source files provides a path "relative to your workspace root."
-    #
-    # Changing to the WORKSPACE root avoids 'file not found' errors when the `.update` target is run
-    # from different directories within the WORKSPACE.
-    requirements_txt = os.path.join(os.environ["BUILD_WORKSPACE_DIRECTORY"], requirements_txt)
-else:
-    err_msg = (
-        "Expected to find BUILD_WORKSPACE_DIRECTORY (running under `bazel run`) or "
-        "TEST_TMPDIR (running under `bazel test`) in environment."
-    )
-    print(
-        err_msg,
-        file=sys.stderr,
-    )
-    sys.exit(1)
-
-update_target_pkg = "/".join(requirements_in.split("/")[:-1])
-# $(rootpath) in the workspace root gives ./requirements.in
-if update_target_pkg == ".":
-    update_target_pkg = ""
-update_command = os.getenv("CUSTOM_COMPILE_COMMAND") or "bazel run %s" % (
-    update_target_label,
-)
-
-os.environ["CUSTOM_COMPILE_COMMAND"] = update_command
-os.environ["PIP_CONFIG_FILE"] = os.getenv("PIP_CONFIG_FILE") or os.devnull
-
-sys.argv.append("--generate-hashes")
-sys.argv.append("--output-file")
-sys.argv.append(requirements_txt if UPDATE else requirements_out)
-sys.argv.append(requirements_in)
-
-if UPDATE:
-    print("Updating " + requirements_txt)
-    cli()
-else:
-    # cli will exit(0) on success
-    try:
-        print("Checking " + requirements_txt)
-        cli()
-        print("cli() should exit", file=sys.stderr)
+if __name__ == "__main__":
+    if len(sys.argv) < 4:
+        print(
+            "Expected at least two arguments: requirements_in requirements_out",
+            file=sys.stderr,
+        )
         sys.exit(1)
-    except SystemExit as e:
-        if e.code == 2:
-            print(
-                "pip-compile exited with code 2. This means that pip-compile found "
-                "incompatible requirements or could not find a version that matches "
-                f"the install requirement in {requirements_in}.",
-                file=sys.stderr,
-            )
-            sys.exit(1)
-        elif e.code == 0:
-            golden = open(requirements_txt).readlines()
-            out = open(requirements_out).readlines()
-            if golden != out:
-                import difflib
 
-                print("".join(difflib.unified_diff(golden, out)), file=sys.stderr)
+    parse_str_none = lambda s: None if s == "None" else s
+
+    requirements_in = os.path.relpath(sys.argv.pop(1))
+    requirements_txt = os.path.relpath(sys.argv.pop(1))
+    requirements_linux = parse_str_none(sys.argv.pop(1))
+    requirements_darwin = parse_str_none(sys.argv.pop(1))
+    requirements_windows = parse_str_none(sys.argv.pop(1))
+    parts = requirements_in.split(os.path.sep, 2)
+    if parts[0] == "external":
+        requirements_in = parts[2]
+        requirements_txt = requirements_txt if "BUILD_WORKSPACE_DIRECTORY" in os.environ else os.path.join("..", "..", requirements_txt)
+        os.chdir(os.path.join(parts[0], parts[1]))
+    update_target_label = sys.argv.pop(1)
+
+    # Before loading click, set the locale for its parser.
+    # If it leaks through to the system setting, it may fail:
+    # RuntimeError: Click will abort further execution because Python 3 was configured to use ASCII
+    # as encoding for the environment. Consult https://click.palletsprojects.com/python3/ for
+    # mitigation steps.
+    os.environ["LC_ALL"] = "C.UTF-8"
+    os.environ["LANG"] = "C.UTF-8"
+
+    UPDATE = True
+    # Detect if we are running under `bazel test`
+    if "TEST_TMPDIR" in os.environ:
+        UPDATE = False
+        # pip-compile wants the cache files to be writeable, but if we point
+        # to the real user cache, Bazel sandboxing makes the file read-only
+        # and we fail.
+        # In theory this makes the test more hermetic as well.
+        sys.argv.append("--cache-dir")
+        sys.argv.append(os.environ["TEST_TMPDIR"])
+        # Make a copy for pip-compile to read and mutate
+        requirements_out = os.path.join(
+            os.environ["TEST_TMPDIR"], os.path.basename(requirements_txt) + ".out"
+        )
+        copyfile(requirements_txt, requirements_out)
+
+    elif "BUILD_WORKSPACE_DIRECTORY" in os.environ:
+        # This value, populated when running under `bazel run`, is a path to the
+        # "root of the workspace where the build was run."
+        # This matches up with the values passed in via the macro using the 'rootpath' Make variable,
+        # which for source files provides a path "relative to your workspace root."
+        #
+        # Changing to the WORKSPACE root avoids 'file not found' errors when the `.update` target is run
+        # from different directories within the WORKSPACE.
+        requirements_txt = os.path.join(os.environ["BUILD_WORKSPACE_DIRECTORY"], requirements_txt)
+    else:
+        err_msg = (
+            "Expected to find BUILD_WORKSPACE_DIRECTORY (running under `bazel run`) or "
+            "TEST_TMPDIR (running under `bazel test`) in environment."
+        )
+        print(
+            err_msg,
+            file=sys.stderr,
+        )
+        sys.exit(1)
+
+    update_command = os.getenv("CUSTOM_COMPILE_COMMAND") or "bazel run %s" % (
+        update_target_label,
+    )
+
+    os.environ["CUSTOM_COMPILE_COMMAND"] = update_command
+    os.environ["PIP_CONFIG_FILE"] = os.getenv("PIP_CONFIG_FILE") or os.devnull
+
+    sys.argv.append("--generate-hashes")
+    sys.argv.append("--output-file")
+    sys.argv.append(requirements_txt if UPDATE else requirements_out)
+    sys.argv.append(requirements_in)
+
+    if UPDATE:
+        print("Updating " + requirements_txt)
+        cli()
+    else:
+        # cli will exit(0) on success
+        try:
+            print("Checking " + requirements_txt)
+            cli()
+            print("cli() should exit", file=sys.stderr)
+            sys.exit(1)
+        except SystemExit as e:
+            if e.code == 2:
                 print(
-                    "Lock file out of date. Run '" + update_command + "' to update.",
+                    "pip-compile exited with code 2. This means that pip-compile found "
+                    "incompatible requirements or could not find a version that matches "
+                    f"the install requirement in {requirements_in}.",
                     file=sys.stderr,
                 )
                 sys.exit(1)
-            sys.exit(0)
-        else:
-            print(
-                f"pip-compile unexpectedly exited with code {e.code}.", file=sys.stderr
-            )
-            sys.exit(1)
+            elif e.code == 0:
+                golden_filename = _select_golden_requirements_file(
+                    requirements_txt,
+                    requirements_darwin,
+                    requirements_linux,
+                    requirements_windows,
+                )
+                golden = open(golden_filename).readlines()
+                out = open(requirements_out).readlines()
+                if golden != out:
+                    import difflib
+
+                    print("".join(difflib.unified_diff(golden, out)), file=sys.stderr)
+                    print(
+                        "Lock file out of date. Run '"
+                        + update_command
+                        + "' to update.",
+                        file=sys.stderr,
+                    )
+                    sys.exit(1)
+                sys.exit(0)
+            else:
+                print(
+                    f"pip-compile unexpectedly exited with code {e.code}.",
+                    file=sys.stderr,
+                )
+                sys.exit(1)
diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl
index d9888a2..743d3e3 100644
--- a/python/pip_install/pip_repository.bzl
+++ b/python/pip_install/pip_repository.bzl
@@ -1,8 +1,13 @@
 ""
 
+load("//python:repositories.bzl", "STANDALONE_INTERPRETER_FILENAME")
 load("//python/pip_install:repositories.bzl", "all_requirements")
 load("//python/pip_install/private:srcs.bzl", "PIP_INSTALL_PY_SRCS")
 
+CPPFLAGS = "CPPFLAGS"
+
+COMMAND_LINE_TOOLS_PATH_SLUG = "commandlinetools"
+
 def _construct_pypath(rctx):
     """Helper function to construct a PYTHONPATH.
 
@@ -61,6 +66,29 @@
             fail("python interpreter `{}` not found in PATH".format(python_interpreter))
     return python_interpreter
 
+def _maybe_set_xcode_location_cflags(rctx, environment):
+    """Patch environment with CPPFLAGS of xcode sdk location.
+
+    Figure out if this interpreter target comes from rules_python, and patch the xcode sdk location if so.
+    Pip won't be able to compile c extensions from sdists with the pre built python distributions from indygreg
+    otherwise. See https://github.com/indygreg/python-build-standalone/issues/103
+    """
+    if (
+        rctx.os.name.lower().startswith("mac os") and
+        rctx.attr.python_interpreter_target != None and
+        rctx.path(Label("@{}//:{}".format(rctx.attr.python_interpreter_target.workspace_name, STANDALONE_INTERPRETER_FILENAME))) and
+        not environment.get(CPPFLAGS)
+    ):
+        xcode_sdk_location = rctx.execute(["xcode-select", "--print-path"])
+        if xcode_sdk_location.return_code == 0:
+            xcode_root = xcode_sdk_location.stdout.strip()
+            if COMMAND_LINE_TOOLS_PATH_SLUG not in xcode_root.lower():
+                # This is a full xcode installation somewhere like /Applications/Xcode13.0.app/Contents/Developer
+                # so we need to change the path to to the macos specific tools which are in a different relative
+                # path than xcode installed command line tools.
+                xcode_root = "{}/Platforms/MacOSX.platform/Developer".format(xcode_root)
+            environment[CPPFLAGS] = "-isysroot {}/SDKs/MacOSX.sdk".format(xcode_root)
+
 def _parse_optional_attrs(rctx, args):
     """Helper function to parse common attributes of pip_repository and whl_library repository rules.
 
@@ -112,6 +140,17 @@
 
     return args
 
+def _create_repository_execution_environment(rctx):
+    """Create a environment dictionary for processes we spawn with rctx.execute.
+
+    Args:
+        rctx: The repository context.
+    Returns: Dictionary of envrionment variable suitable to pass to rctx.execute.
+    """
+    env = {"PYTHONPATH": _construct_pypath(rctx)}
+    _maybe_set_xcode_location_cflags(rctx, env)
+    return env
+
 _BUILD_FILE_CONTENTS = """\
 package(default_visibility = ["//visibility:public"])
 
@@ -186,7 +225,7 @@
     result = rctx.execute(
         args,
         # Manually construct the PYTHONPATH since we cannot use the toolchain here
-        environment = {"PYTHONPATH": _construct_pypath(rctx)},
+        environment = _create_repository_execution_environment(rctx),
         timeout = rctx.attr.timeout,
         quiet = rctx.attr.quiet,
     )
@@ -390,7 +429,7 @@
     result = rctx.execute(
         args,
         # Manually construct the PYTHONPATH since we cannot use the toolchain here
-        environment = {"PYTHONPATH": _construct_pypath(rctx)},
+        environment = _create_repository_execution_environment(rctx),
         quiet = rctx.attr.quiet,
         timeout = rctx.attr.timeout,
     )
diff --git a/python/pip_install/requirements.bzl b/python/pip_install/requirements.bzl
index 0035e7c..0c66133 100644
--- a/python/pip_install/requirements.bzl
+++ b/python/pip_install/requirements.bzl
@@ -9,6 +9,9 @@
         visibility = ["//visibility:private"],
         requirements_in = None,
         requirements_txt = None,
+        requirements_linux = None,
+        requirements_darwin = None,
+        requirements_windows = None,
         tags = None,
         **kwargs):
     """Generates targets for managing pip dependencies with pip-compile.
@@ -28,6 +31,9 @@
         visibility: passed to both the _test and .update rules
         requirements_in: file expressing desired dependencies
         requirements_txt: result of "compiling" the requirements.in file
+        requirements_linux: File of linux specific resolve output to check validate if requirement.in has changes.
+        requirements_darwin: File of darwin specific resolve output to check validate if requirement.in has changes.
+        requirements_windows: File of windows specific resolve output to check validate if requirement.in has changes.
         tags: tagging attribute common to all build rules, passed to both the _test and .update rules
         **kwargs: other bazel attributes passed to the "_test" rule
     """
@@ -43,17 +49,21 @@
         visibility = visibility,
     )
 
-    data = [name, requirements_in, requirements_txt]
+    data = [name, requirements_in, requirements_txt] + [f for f in (requirements_linux, requirements_darwin, requirements_windows) if f != None]
 
     # Use the Label constructor so this is expanded in the context of the file
     # where it appears, which is to say, in @rules_python
     pip_compile = Label("//python/pip_install:pip_compile.py")
 
-    loc = "$(rootpath %s)"
+    loc = "$(rootpath {})"
 
     args = [
-        loc % requirements_in,
-        loc % requirements_txt,
+        loc.format(requirements_in),
+        loc.format(requirements_txt),
+        # String None is a placeholder for argv ordering.
+        loc.format(requirements_linux) if requirements_linux else "None",
+        loc.format(requirements_darwin) if requirements_darwin else "None",
+        loc.format(requirements_windows) if requirements_windows else "None",
         "//%s:%s.update" % (native.package_name(), name),
     ] + extra_args
 
diff --git a/python/repositories.bzl b/python/repositories.bzl
index dc3ca06..1441432 100644
--- a/python/repositories.bzl
+++ b/python/repositories.bzl
@@ -35,6 +35,8 @@
 # Remaining content of the file is only used to support toolchains.
 ########
 
+STANDALONE_INTERPRETER_FILENAME = "STANDALONE_INTERPRETER"
+
 def _python_repository_impl(rctx):
     if rctx.attr.distutils and rctx.attr.distutils_content:
         fail("Only one of (distutils, distutils_content) should be set.")
@@ -187,6 +189,7 @@
         python_path = python_bin,
         python_version = python_short_version,
     )
+    rctx.file(STANDALONE_INTERPRETER_FILENAME, "# File intentionally left blank. Indicates that this is an interpreter repo created by rules_python.")
     rctx.file("BUILD.bazel", build_content)
 
     return {