content: #!/usr/bin/env python
  # Copyright (c) Meta Platforms, Inc. and affiliates.
  #
  # This source code is licensed under the MIT license found in the
  # LICENSE file in the root directory of this source tree.
  
  from pathlib import Path
  import os
  import setuptools
  import sys
  
  try:
      import torch
      from torch.utils import cpp_extension as torch_cpp_ext
  
      # This is a hack to get CUDAExtension to compile with
      #   -ltorch_cuda
      # instead of split
      #   -ltorch_cuda_cu -ltorch_cuda_cpp
      torch_cpp_ext.BUILD_SPLIT_CUDA = False
  
      if hasattr(torch_cpp_ext, "CUDA_GCC_VERSIONS"):
          # hack to be able to compile with gcc-8.4.0
          torch_cpp_ext.CUDA_GCC_VERSIONS["10.2"] = (
              torch_cpp_ext.MINIMUM_GCC_VERSION,
              (8, 4, 99),
          )
  
      torch_version = torch.__version__.split(".")
      torch_geq_113 = (
          int(torch_version[0]) > 1
          or int(torch_version[0]) == 1
          and int(torch_version[1]) >= 13
      )
  except ModuleNotFoundError:
      print("Theseus installation requires torch.")
      sys.exit(1)
  
  
  def parse_requirements_file(path):
      with open(path) as f:
          reqs = []
          for line in f:
              if "functorch" in line and torch_geq_113:
                  # Don't install functorch 0.2.1 if torch 1.13 already
                  # installed
                  continue
              line = line.strip()
              reqs.append(line)
      return reqs
  
  
  def get_baspacho_info(baspacho_root_dir, has_cuda):
      baspacho_build_dir = Path(baspacho_root_dir) / "build"
      include_dirs = [
          str(baspacho_root_dir),
          str(baspacho_build_dir / "_deps" / "eigen-src"),
      ]
      library_dirs = [
          str(baspacho_build_dir / "baspacho" / "baspacho"),
      ]
      libraries = ["BaSpaCho"]
      if has_cuda:
          libraries.append("cusolver")
          libraries.append("cublas")
      return include_dirs, library_dirs, libraries
  
  
  def maybe_create_baspacho_extension(has_cuda):
      baspacho_root_dir = os.environ.get("BASPACHO_ROOT_DIR", None)
      if baspacho_root_dir is None:
          print("No BaSpaCho dir given, so extension will not be installed.")
          return None
      ext_cls = torch_cpp_ext.CUDAExtension if has_cuda else torch_cpp_ext.CppExtension
      sources = ["theseus/extlib/baspacho_solver.cpp"]
      define_macros = [("NO_BASPACHO_CHECKS", "1")]
      if has_cuda:
          sources.append("theseus/extlib/baspacho_solver_cuda.cu")
          define_macros.append(("THESEUS_HAVE_CUDA", "1"))
      include_dirs, library_dirs, libraries = get_baspacho_info(
          baspacho_root_dir, has_cuda
      )
      return ext_cls(
          name="theseus.extlib.baspacho_solver",
          sources=sources,
          define_macros=define_macros,
          include_dirs=include_dirs,
          library_dirs=library_dirs,
          libraries=libraries,
      )
  
  
  reqs_main = parse_requirements_file("requirements/main.txt")
  reqs_dev = parse_requirements_file("requirements/dev.txt")
  root_dir = Path(__file__).parent
  
  is_nightly = False
  nightly_date_str = os.environ.get("THESEUS_NIGHTLY", None)
  if nightly_date_str is not None:
      from datetime import date, datetime
  
      nightly_date = datetime.strptime(nightly_date_str, "%Y.%m.%d").date()
      assert nightly_date == date.today(), (
          f"THESEUS_NIGHTLY must be set to today's date in format %Y.%-m.%-d (stripped) "
          f"but got {nightly_date_str}."
      )
      print(f"Building nightly with date {nightly_date_str}")
      is_nightly = True
  
  if is_nightly:
      version = nightly_date_str
  else:
      with open(Path("theseus") / "_version.py", "r") as f:
          for line in f:
              if "__version__ = " in line:
                  version = line.split("__version__ = ")[1].rstrip().strip('"')
  
  with open("README.md", "r") as fh:
      long_description = fh.read()
  
  # Add C++ and CUDA extensions
  compile_cuda_flag = os.environ.get("THESEUS_FORCE_CUDA")
  compile_cuda_support = (
      torch.cuda.is_available()
      if (compile_cuda_flag is None)
      else (compile_cuda_flag not in {"", "0", "False"})
  )
  cuda_detection_info = (
      "detected" if compile_cuda_flag is None else "forced by THESEUS_FORCE_CUDA env var"
  )
  print(f"Theseus CUDA support: {compile_cuda_support} ({cuda_detection_info})")
  
  if compile_cuda_support:
      ext_modules = [
          # reference: https://docs.python.org/3/distutils/apiref.html#distutils.core.Extension
          torch_cpp_ext.CUDAExtension(
              name="theseus.extlib.mat_mult",
              sources=[str(root_dir / "theseus" / "extlib" / "mat_mult.cu")],
          ),
          torch_cpp_ext.CUDAExtension(
              name="theseus.extlib.cusolver_lu_solver",
              sources=[
                  str(root_dir / "theseus" / "extlib" / "cusolver_lu_solver.cpp"),
                  str(root_dir / "theseus" / "extlib" / "cusolver_sp_defs.cpp"),
              ],
              include_dirs=[str(root_dir)],
              libraries=["cusolver", "cusparse"],
          ),
      ]
  else:
      print("No CUDA support found. CUDA extensions won't be installed.")
      ext_modules = []
  baspacho_extension = maybe_create_baspacho_extension(compile_cuda_support)
  if baspacho_extension is not None:
      ext_modules.append(baspacho_extension)
  
  excluded_packages = ["torchlie", "torchlie.*", "tests*", "tests", "examples"]
  package_name = "theseus-ai-nightly" if is_nightly else "theseus-ai"
  if not os.environ.get("INCLUDE_THESEUS_LABS") and not is_nightly:
      excluded_packages.append("theseus.labs*")
      print("Excluding theseus.labs")
  setuptools.setup(
      name=package_name,
      version=version,
      author="Meta Research",
      description="A library for differentiable nonlinear optimization.",
      long_description=long_description,
      long_description_content_type="text/markdown",
      url="https://github.com/facebookresearch/theseus",
      keywords="differentiable optimization, nonlinear least squares, factor graphs",
      packages=setuptools.find_packages(exclude=tuple(excluded_packages)),
      classifiers=[
          "Programming Language :: Python :: 3",
          "License :: OSI Approved :: MIT License",
          "Intended Audience :: Science/Research",
          "Topic :: Scientific/Engineering :: Artificial Intelligence",
      ],
      python_requires=">=3.8",
      install_requires=reqs_main,
      extras_require={"dev": reqs_main + reqs_dev},
      cmdclass={"build_ext": torch_cpp_ext.BuildExtension},
      ext_modules=ext_modules,
  )
  