<filename>setup.py
from setuptools import setup, find_packages
from pathlib import Path
import os
import sys

import torch
from torch.utils.cpp_extension import BuildExtension, CppExtension, CUDAExtension, CUDA_HOME


def resolve_requirements(file):
    requirements = []
    with open(file) as f:
        req = f.read().splitlines()
        for r in req:
            if r.startswith("-r"):
                requirements += resolve_requirements(
                    os.path.join(os.path.dirname(file), r.split(" ")[1]))
            else:
                requirements.append(r)
    return requirements


def read_file(file):
    with open(file) as f:
        content = f.read()
    return content


def clean():
    """Custom clean command to tidy up the project root."""
    os.system('rm -vrf ./build ./dist ./*.pyc ./*.tgz')


def get_extensions():
    """
    Adapted from https://github.com/pytorch/vision/blob/master/setup.py
    and https://github.com/facebookresearch/detectron2/blob/master/setup.py
    """
    print("Build csrc")
    print("Building with {}".format(sys.version_info))

    this_dir = Path(os.path.dirname(os.path.abspath(__file__)))
    extensions_dir = this_dir/'nndet'/'csrc'

    main_file = list(extensions_dir.glob('*.cpp'))
    source_cpu = []  # list((extensions_dir/'cpu').glob('*.cpp')) temporary until I added header files ...
    source_cuda = list((extensions_dir/'cuda').glob('*.cu'))
    print("main_file {}".format(main_file))
    print("source_cpu {}".format(source_cpu))
    print("source_cuda {}".format(source_cuda))

    sources = main_file + source_cpu
    extension = CppExtension

    define_macros = []
    extra_compile_args = {"cxx": []}

    if (torch.cuda.is_available() and CUDA_HOME is not None) or os.getenv('FORCE_CUDA', '0') == '1':
        print("Adding CUDA csrc to build")
        print("CUDA ARCH {}".format(os.getenv("TORCH_CUDA_ARCH_LIST")))
        extension = CUDAExtension
        sources += source_cuda
        define_macros += [('WITH_CUDA', None)]
        extra_compile_args["nvcc"] = [
            "-DCUDA_HAS_FP16=1",
            "-D__CUDA_NO_HALF_OPERATORS__",
            "-D__CUDA_NO_HALF_CONVERSIONS__",
            "-D__CUDA_NO_HALF2_OPERATORS__",
        ]
        
        # It's better if pytorch can do this by default ..
        CC = os.environ.get("CC", None)
        if CC is not None:
            extra_compile_args["nvcc"].append("-ccbin={}".format(CC))

    sources = [os.path.join(extensions_dir, s) for s in sources]
    include_dirs = [str(extensions_dir)]
    
    ext_modules = [
        extension(
            'nndet._C',
            sources,
            include_dirs=include_dirs,
            define_macros=define_macros,
            extra_compile_args=extra_compile_args,
        )
    ]
    
    return ext_modules

requirements = resolve_requirements(os.path.join(os.path.dirname(__file__),
                                                 'requirements.txt'))
readme = read_file(os.path.join(os.path.dirname(__file__), "README.md"))

setup(
    name='nndet',
    version="v0.1",
    packages=find_packages(),
    include_package_data=True,
    test_suite="unittest",
    long_description=readme,
    long_description_content_type='text/markdown',
    install_requires=requirements,
    tests_require=["coverage"],
    python_requires=">=3.8",
    author="Division of Medical Image Computing, German Cancer Research Center",
    maintainer_email='<EMAIL>',
    ext_modules=get_extensions(),
    cmdclass={
        'build_ext': BuildExtension,
        'clean': clean,
    },
    entry_points={
        'console_scripts': [
            'nndet_example = scripts.generate_example:main',

            'nndet_prep = scripts.preprocess:main',
            'nndet_cls2fg = scripts.convert_cls2fg:main',
            'nndet_seg2det = scripts.convert_seg2det:main',

            'nndet_train = scripts.train:train',
            'nndet_sweep = scripts.train:sweep',

            'nndet_eval = scripts.train:evaluate',
            'nndet_predict = scripts.predict:main',
            'nndet_consolidate = scripts.consolidate:main',

            'nndet_boxes2nii = scripts.utils:boxes2nii',
            'nndet_seg2nii = scripts.utils:seg2nii',
            'nndet_unpack = scripts.utils:unpack',
            'nndet_env = scripts.utils:env',
        ]
    },
)

<filename>setup.py
from setuptools import setup, find_packages
from pathlib import Path
import os
import sys

import torch
from torch.utils.cpp_extension import BuildExtension, CppExtension, CUDAExtension, CUDA_HOME


def resolve_requirements(file):
    requirements = []
    with open(file) as f:
        req = f.read().splitlines()
        for r in req:
            if r.startswith("-r"):
                requirements += resolve_requirements(
                    os.path.join(os.path.dirname(file), r.split(" ")[1]))
            else:
                requirements.append(r)
    return requirements


def read_file(file):
    with open(file) as f:
        content = f.read()
    return content


def clean():
    """Custom clean command to tidy up the project root."""
    os.system('rm -vrf ./build ./dist ./*.pyc ./*.tgz')


def get_extensions():
    """
    Adapted from https://github.com/pytorch/vision/blob/master/setup.py
    and https://github.com/facebookresearch/detectron2/blob/master/setup.py
    """
    print("Build csrc")
    print("Building with {}".format(sys.version_info))

    this_dir = Path(os.path.dirname(os.path.abspath(__file__)))
    extensions_dir = this_dir/'nndet'/'csrc'

    main_file = list(extensions_dir.glob('*.cpp'))
    source_cpu = []  # list((extensions_dir/'cpu').glob('*.cpp')) temporary until I added header files ...
    source_cuda = list((extensions_dir/'cuda').glob('*.cu'))
    print("main_file {}".format(main_file))
    print("source_cpu {}".format(source_cpu))
    print("source_cuda {}".format(source_cuda))

    sources = main_file + source_cpu
    extension = CppExtension

    define_macros = []
    extra_compile_args = {"cxx": []}

    if (torch.cuda.is_available() and CUDA_HOME is not None) or os.getenv('FORCE_CUDA', '0') == '1':
        print("Adding CUDA csrc to build")
        print("CUDA ARCH {}".format(os.getenv("TORCH_CUDA_ARCH_LIST")))
        extension = CUDAExtension
        sources += source_cuda
        define_macros += [('WITH_CUDA', None)]
        extra_compile_args["nvcc"] = [
            "-DCUDA_HAS_FP16=1",
            "-D__CUDA_NO_HALF_OPERATORS__",
            "-D__CUDA_NO_HALF_CONVERSIONS__",
            "-D__CUDA_NO_HALF2_OPERATORS__",
        ]
        
        # It's better if pytorch can do this by default ..
        CC = os.environ.get("CC", None)
        if CC is not None:
            extra_compile_args["nvcc"].append("-ccbin={}".format(CC))

    sources = [os.path.join(extensions_dir, s) for s in sources]
    include_dirs = [str(extensions_dir)]
    
    ext_modules = [
        extension(
            'nndet._C',
            sources,
            include_dirs=include_dirs,
            define_macros=define_macros,
            extra_compile_args=extra_compile_args,
        )
    ]
    
    return ext_modules

requirements = resolve_requirements(os.path.join(os.path.dirname(__file__),
                                                 'requirements.txt'))
readme = read_file(os.path.join(os.path.dirname(__file__), "README.md"))

setup(
    name='nndet',
    version="v0.1",
    packages=find_packages(),
    include_package_data=True,
    test_suite="unittest",
    long_description=readme,
    long_description_content_type='text/markdown',
    install_requires=requirements,
    tests_require=["coverage"],
    python_requires=">=3.8",
    author="Division of Medical Image Computing, German Cancer Research Center",
    maintainer_email='<EMAIL>',
    ext_modules=get_extensions(),
    cmdclass={
        'build_ext': BuildExtension,
        'clean': clean,
    },
    entry_points={
        'console_scripts': [
            'nndet_example = scripts.generate_example:main',

            'nndet_prep = scripts.preprocess:main',
            'nndet_cls2fg = scripts.convert_cls2fg:main',
            'nndet_seg2det = scripts.convert_seg2det:main',

            'nndet_train = scripts.train:train',
            'nndet_sweep = scripts.train:sweep',

            'nndet_eval = scripts.train:evaluate',
            'nndet_predict = scripts.predict:main',
            'nndet_consolidate = scripts.consolidate:main',

            'nndet_boxes2nii = scripts.utils:boxes2nii',
            'nndet_seg2nii = scripts.utils:seg2nii',
            'nndet_unpack = scripts.utils:unpack',
            'nndet_env = scripts.utils:env',
        ]
    },
)

Custom clean command to tidy up the project root. Adapted from https://github.com/pytorch/vision/blob/master/setup.py     and https://github.com/facebookresearch/detectron2/blob/master/setup.py # list((extensions_dir/'cpu').glob('*.cpp')) temporary until I added header files ... # It's better if pytorch can do this by default ..