python setuptools compile fortran code and make an entry points

It's actually a pretty simple trick. Just import setuptools before importing setup from numpy.distutils.core and you're good to go. The explanation for this is that numpy.distutils is much more than just the vanilla distutils with some package-specific tweaks. In particular, numpy.distutils checks whether setuptools is available and if so, uses it where possible under the hood. If you're interested, look at the module's source code, paying attention to the usages of have_setuptools flag.

As usual, a Minimal, Complete, and Verifiable example:

so-55352409/
├── spam
│   ├── __init__.py
│   ├── cli.py
│   └── libfib.f90
└── setup.py

setup.py:

import setuptools  # this is the "magic" import
from numpy.distutils.core import setup, Extension


lib = Extension(name='spam.libfib', sources=['spam/libfib.f90'])

setup(
    name = 'spamlib',
    packages = ['spam'],
    ext_modules = [lib],
    entry_points={
        'console_scripts': [
            'hello = spam.cli:main',
        ],
    }
)

spam/cli.py:

from spam.libfib import fib


def main():
    print(fib(10))

spam/libfib.f90:

C FILE: LIBFIB.F90
      SUBROUTINE FIB(A,N)
C
C     CALCULATE FIRST N FIBONACCI NUMBERS
C
      INTEGER N
      REAL*8 A(N)
Cf2py intent(in) n
Cf2py intent(out) a
Cf2py depend(n) a
      DO I=1,N
         IF (I.EQ.1) THEN
            A(I) = 0.0D0
         ELSEIF (I.EQ.2) THEN
            A(I) = 1.0D0
         ELSE 
            A(I) = A(I-1) + A(I-2)
         ENDIF
      ENDDO
      END
C END FILE LIBFIB.F90

Build and install the package:

$ cd so-55352409
$ python setup.py bdist_wheel
...
$ pip install dist/spamlib-0.0.0-cp36-cp36m-linux_x86_64.whl
...
$ hello
[ 0.  1.  1.  2.  3.  5.  8. 13. 21. 34.]