Repository: tensorflow/addons

Issue:
Custom Op Linux ABI Incompatibility: Undefined Symbol
Creating this issue to consolidate the information. As seen in https://github.com/tensorflow/addons/issues/676 https://github.com/tensorflow/addons/issues/574

## Overview:
The TF C++ API for kernel implementations are not ABI stable. Because of this we compile our pip package to be manylinux2010 compatible with GCC 7.3.1. This means that TF-Addons custom ops will work on pip installed TF, but are not guaranteed to work with TF built from source or installed from conda

This should not affect our macOS and Windows versions.

## Temporary "fixes"
We implemented a lazy loading of custom-ops so majority of TFA functionality is not affected by this issue:
https://github.com/tensorflow/addons/pull/869

## Long term solution
[RFC 133](https://github.com/tensorflow/community/pull/133) is in the works to make a stable C ABI. 


Discussion:
I am seeing the undefined symbol problem with a custom built TF 1.14 python whl.  What  bazel build option should I use beside  --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"  ? How do I specify compatibility with manylinux2010  and GCC 7.3.1



> I am seeing the undefined symbol problem with a custom built TF 1.14 python whl. What bazel build option should I use beside --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0" ? How do I specify compatibility with manylinux2010 and GCC 7.3.1

TensorFlow Addons only supports TF2.x. We have an issue for build from source compatibility but it would still only support TF2+ https://github.com/tensorflow/addons/issues/770
Addons are similar to CustomOps in 1.x , right ?  So has the same issue.

Resolving patch:
diff --git a/configure.py b/configure.py
--- a/configure.py
+++ b/configure.py
@@ -145,6 +145,7 @@ def create_build_configuration():
             write("build --copt=-mavx")
         write("build --cxxopt=-std=c++14")
         write("build --host_cxxopt=-std=c++14")
+        write('build --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"')
 
     if os.getenv("TF_NEED_CUDA", "0") == "1":
         print("> Building GPU & CPU ops")
diff --git a/tensorflow_addons/utils/ensure_tf_install.py b/tensorflow_addons/utils/ensure_tf_install.py
--- a/tensorflow_addons/utils/ensure_tf_install.py
+++ b/tensorflow_addons/utils/ensure_tf_install.py
@@ -18,7 +18,7 @@
 # needs to happen before anything else, since the imports below will try to
 # import TensorFlow, too.
 
-from distutils.version import LooseVersion
+from packaging.version import Version
 import warnings
 
 import tensorflow as tf
@@ -44,10 +44,10 @@ def _check_tf_version():
         )
         return
 
-    min_version = LooseVersion(INCLUSIVE_MIN_TF_VERSION)
-    max_version = LooseVersion(EXCLUSIVE_MAX_TF_VERSION)
+    min_version = Version(INCLUSIVE_MIN_TF_VERSION)
+    max_version = Version(EXCLUSIVE_MAX_TF_VERSION)
 
-    if min_version <= LooseVersion(tf.__version__) < max_version:
+    if min_version <= Version(tf.__version__) < max_version:
         return
 
     warnings.warn(
diff --git a/tensorflow_addons/utils/resource_loader.py b/tensorflow_addons/utils/resource_loader.py
--- a/tensorflow_addons/utils/resource_loader.py
+++ b/tensorflow_addons/utils/resource_loader.py
@@ -14,7 +14,7 @@
 # ==============================================================================
 """Utilities similar to tf.python.platform.resource_loader."""
 
-from distutils.version import LooseVersion
+from packaging.version import Version
 import os
 import warnings
 
@@ -117,6 +117,6 @@ def abi_is_compatible():
         # tf-nightly
         return False
 
-    min_version = LooseVersion(INCLUSIVE_MIN_TF_VERSION_FOR_ABI_COMPATIBILITY)
-    max_version = LooseVersion(EXCLUSIVE_MAX_TF_VERSION_FOR_ABI_COMPATIBILITY)
-    return min_version <= LooseVersion(tf.__version__) < max_version
+    min_version = Version(INCLUSIVE_MIN_TF_VERSION_FOR_ABI_COMPATIBILITY)
+    max_version = Version(EXCLUSIVE_MAX_TF_VERSION_FOR_ABI_COMPATIBILITY)
+    return min_version <= Version(tf.__version__) < max_version


Test patch:
diff --git a/tensorflow_addons/text/tests/crf_test.py b/tensorflow_addons/text/tests/crf_test.py
--- a/tensorflow_addons/text/tests/crf_test.py
+++ b/tensorflow_addons/text/tests/crf_test.py
@@ -15,7 +15,7 @@
 """Tests for CRF."""
 
 import itertools
-from distutils.version import LooseVersion
+from packaging.version import Version
 
 import pytest
 import numpy as np
@@ -536,7 +536,7 @@ def call(self, y_true, y_pred):
 
     tensor_name = (
         "tf.math.multiply"
-        if LooseVersion(tf.__version__) >= "2.5.0"
+        if Version(tf.__version__) >= Version("2.5.0")
         else "tf_op_layer_Mul"
     )
     y_data = {tensor_name: np.random.randint(0, 3, (5, 10))}