1import os, sys, subprocess
2import os.path as osp
3import configparser
4from setuptools import setup, Extension
5from distutils.dist import Distribution
6
7setuptools_extra_kwargs = {
8    "install_requires": ["numpy>=1.9","cftime"],
9    "setup_requires": ['setuptools>=18.0', "cython>=0.19"],
10    "entry_points": {
11        'console_scripts': [
12            'ncinfo = netCDF4.utils:ncinfo',
13            'nc4tonc3 = netCDF4.utils:nc4tonc3',
14            'nc3tonc4 = netCDF4.utils:nc3tonc4',
15        ]
16    },
17}
18
19open_kwargs = {'encoding': 'utf-8'}
20
21
22def check_hdf5version(hdf5_includedir):
23    try:
24        f = open(os.path.join(hdf5_includedir, 'H5public.h'), **open_kwargs)
25    except IOError:
26        return None
27    hdf5_version = None
28    for line in f:
29        if line.startswith('#define H5_VERS_INFO'):
30            hdf5_version = line.split('"')[1]
31    return hdf5_version
32
33def get_hdf5_version(direc):
34    # check to see if hdf5 headers in direc, return version number or None
35    hdf5_version = None
36    sys.stdout.write('checking %s ...\n' % direc)
37    hdf5_version = check_hdf5version(direc)
38    if hdf5_version is None:
39        sys.stdout.write('hdf5 headers not found in %s\n' % direc)
40        return None
41    else:
42        sys.stdout.write('%s headers found in %s\n' %
43                        (hdf5_version,direc))
44        return hdf5_version
45
46def check_ifnetcdf4(netcdf4_includedir):
47    try:
48        f = open(os.path.join(netcdf4_includedir, 'netcdf.h'), **open_kwargs)
49    except IOError:
50        return False
51    isnetcdf4 = False
52    for line in f:
53        if line.startswith('nc_inq_compound'):
54            isnetcdf4 = True
55    return isnetcdf4
56
57
58def check_api(inc_dirs,netcdf_lib_version):
59    has_rename_grp = False
60    has_nc_inq_path = False
61    has_nc_inq_format_extended = False
62    has_cdf5_format = False
63    has_nc_open_mem = False
64    has_nc_create_mem = False
65    has_parallel_support = False
66    has_parallel4_support = False
67    has_pnetcdf_support = False
68
69    for d in inc_dirs:
70        try:
71            f = open(os.path.join(d, 'netcdf.h'), **open_kwargs)
72        except IOError:
73            continue
74
75        has_nc_open_mem = os.path.exists(os.path.join(d, 'netcdf_mem.h'))
76
77        for line in f:
78            if line.startswith('nc_rename_grp'):
79                has_rename_grp = True
80            if line.startswith('nc_inq_path'):
81                has_nc_inq_path = True
82            if line.startswith('nc_inq_format_extended'):
83                has_nc_inq_format_extended = True
84            if line.startswith('#define NC_FORMAT_64BIT_DATA'):
85                has_cdf5_format = True
86
87        if has_nc_open_mem:
88            try:
89                f = open(os.path.join(d, 'netcdf_mem.h'), **open_kwargs)
90            except IOError:
91                continue
92            for line in f:
93                if line.startswith('EXTERNL int nc_create_mem'):
94                    has_nc_create_mem = True
95
96        ncmetapath = os.path.join(d,'netcdf_meta.h')
97        if os.path.exists(ncmetapath):
98            for line in open(ncmetapath):
99                if line.startswith('#define NC_HAS_CDF5'):
100                    has_cdf5_format = bool(int(line.split()[2]))
101                if line.startswith('#define NC_HAS_PARALLEL'):
102                    has_parallel_support = bool(int(line.split()[2]))
103                if line.startswith('#define NC_HAS_PARALLEL4'):
104                    has_parallel4_support = bool(int(line.split()[2]))
105                if line.startswith('#define NC_HAS_PNETCDF'):
106                    has_pnetcdf_support = bool(int(line.split()[2]))
107        # NC_HAS_PARALLEL4 missing in 4.6.1 (issue #964)
108        if not has_parallel4_support and has_parallel_support and not has_pnetcdf_support:
109            has_parallel4_support = True
110        # for 4.6.1, if NC_HAS_PARALLEL=NC_HAS_PNETCDF=1, guess that
111        # parallel HDF5 is enabled (must guess since there is no
112        # NC_HAS_PARALLEL4)
113        elif netcdf_lib_version == "4.6.1" and not has_parallel4_support and has_parallel_support:
114            has_parallel4_support = True
115        break
116
117    return has_rename_grp, has_nc_inq_path, has_nc_inq_format_extended, \
118           has_cdf5_format, has_nc_open_mem, has_nc_create_mem, \
119           has_parallel4_support, has_pnetcdf_support
120
121
122def getnetcdfvers(libdirs):
123    """
124    Get the version string for the first netcdf lib found in libdirs.
125    (major.minor.release). If nothing found, return None.
126    """
127
128    import os, re, sys, ctypes
129
130    if sys.platform.startswith('win'):
131        regexp = re.compile('^netcdf.dll$')
132    elif sys.platform.startswith('cygwin'):
133        bindirs = []
134        for d in libdirs:
135            bindirs.append(os.path.dirname(d) + '/bin')
136        regexp = re.compile(r'^cygnetcdf-\d.dll')
137    elif sys.platform.startswith('darwin'):
138        regexp = re.compile(r'^libnetcdf.dylib')
139    else:
140        regexp = re.compile(r'^libnetcdf.so')
141
142    if sys.platform.startswith('cygwin'):
143        dirs = bindirs
144    else:
145        dirs = libdirs
146    for d in dirs:
147        try:
148            candidates = [x for x in os.listdir(d) if regexp.match(x)]
149            if len(candidates) != 0:
150                candidates.sort(
151                    key=lambda x: len(x))  # Prefer libfoo.so to libfoo.so.X.Y.Z
152                path = os.path.abspath(os.path.join(d, candidates[0]))
153            lib = ctypes.cdll.LoadLibrary(path)
154            inq_libvers = lib.nc_inq_libvers
155            inq_libvers.restype = ctypes.c_char_p
156            vers = lib.nc_inq_libvers()
157            return vers.split()[0]
158        except Exception:
159            pass  # We skip invalid entries, because that's what the C compiler does
160
161    return None
162
163def extract_version(CYTHON_FNAME):
164    version = None
165    with open(CYTHON_FNAME) as fi:
166        for line in fi:
167            if (line.startswith('__version__')):
168                _, version = line.split('=')
169                version = version.strip()[1:-1]  # Remove quotation characters.
170                break
171    return version
172
173
174HDF5_dir = os.environ.get('HDF5_DIR')
175HDF5_incdir = os.environ.get('HDF5_INCDIR')
176HDF5_libdir = os.environ.get('HDF5_LIBDIR')
177netCDF4_dir = os.environ.get('NETCDF4_DIR')
178netCDF4_incdir = os.environ.get('NETCDF4_INCDIR')
179netCDF4_libdir = os.environ.get('NETCDF4_LIBDIR')
180szip_dir = os.environ.get('SZIP_DIR')
181szip_libdir = os.environ.get('SZIP_LIBDIR')
182szip_incdir = os.environ.get('SZIP_INCDIR')
183hdf4_dir = os.environ.get('HDF4_DIR')
184hdf4_libdir = os.environ.get('HDF4_LIBDIR')
185hdf4_incdir = os.environ.get('HDF4_INCDIR')
186jpeg_dir = os.environ.get('JPEG_DIR')
187jpeg_libdir = os.environ.get('JPEG_LIBDIR')
188jpeg_incdir = os.environ.get('JPEG_INCDIR')
189curl_dir = os.environ.get('CURL_DIR')
190curl_libdir = os.environ.get('CURL_LIBDIR')
191curl_incdir = os.environ.get('CURL_INCDIR')
192mpi_incdir = os.environ.get('MPI_INCDIR')
193
194USE_NCCONFIG = os.environ.get('USE_NCCONFIG')
195if USE_NCCONFIG is not None:
196    USE_NCCONFIG = bool(int(USE_NCCONFIG))
197USE_SETUPCFG = os.environ.get('USE_SETUPCFG')
198# override use of setup.cfg with env var.
199if USE_SETUPCFG is not None:
200    USE_SETUPCFG = bool(int(USE_SETUPCFG))
201else:
202    USE_SETUPCFG = True
203
204setup_cfg = 'setup.cfg'
205# contents of setup.cfg will override env vars, unless
206# USE_SETUPCFG evaluates to False.
207ncconfig = None
208use_ncconfig = None
209if USE_SETUPCFG and os.path.exists(setup_cfg):
210    sys.stdout.write('reading from setup.cfg...\n')
211    config = configparser.ConfigParser()
212    config.read(setup_cfg)
213    try:
214        HDF5_dir = config.get("directories", "HDF5_dir")
215    except:
216        pass
217    try:
218        HDF5_libdir = config.get("directories", "HDF5_libdir")
219    except:
220        pass
221    try:
222        HDF5_incdir = config.get("directories", "HDF5_incdir")
223    except:
224        pass
225    try:
226        netCDF4_dir = config.get("directories", "netCDF4_dir")
227    except:
228        pass
229    try:
230        netCDF4_libdir = config.get("directories", "netCDF4_libdir")
231    except:
232        pass
233    try:
234        netCDF4_incdir = config.get("directories", "netCDF4_incdir")
235    except:
236        pass
237    try:
238        szip_dir = config.get("directories", "szip_dir")
239    except:
240        pass
241    try:
242        szip_libdir = config.get("directories", "szip_libdir")
243    except:
244        pass
245    try:
246        szip_incdir = config.get("directories", "szip_incdir")
247    except:
248        pass
249    try:
250        hdf4_dir = config.get("directories", "hdf4_dir")
251    except:
252        pass
253    try:
254        hdf4_libdir = config.get("directories", "hdf4_libdir")
255    except:
256        pass
257    try:
258        hdf4_incdir = config.get("directories", "hdf4_incdir")
259    except:
260        pass
261    try:
262        jpeg_dir = config.get("directories", "jpeg_dir")
263    except:
264        pass
265    try:
266        jpeg_libdir = config.get("directories", "jpeg_libdir")
267    except:
268        pass
269    try:
270        jpeg_incdir = config.get("directories", "jpeg_incdir")
271    except:
272        pass
273    try:
274        curl_dir = config.get("directories", "curl_dir")
275    except:
276        pass
277    try:
278        curl_libdir = config.get("directories", "curl_libdir")
279    except:
280        pass
281    try:
282        curl_incdir = config.get("directories", "curl_incdir")
283    except:
284        pass
285    try:
286        mpi_incdir = config.get("directories","mpi_incdir")
287    except:
288        pass
289    try:
290        use_ncconfig = config.getboolean("options", "use_ncconfig")
291    except:
292        pass
293    try:
294        ncconfig = config.get("options", "ncconfig")
295    except:
296        pass
297
298try:
299    if ncconfig is None:
300        if netCDF4_dir is not None:
301            ncconfig = os.path.join(netCDF4_dir, 'bin/nc-config')
302        else:  # otherwise, just hope it's in the users PATH.
303            ncconfig = 'nc-config'
304    HAS_NCCONFIG = subprocess.call([ncconfig, '--libs'],
305                                     stdout=subprocess.PIPE) == 0
306except OSError:
307    HAS_NCCONFIG = False
308
309# make sure USE_NCCONFIG from environment takes
310# precendence over use_ncconfig from setup.cfg (issue #341).
311if USE_NCCONFIG is None and use_ncconfig is not None:
312    USE_NCCONFIG = use_ncconfig
313elif USE_NCCONFIG is None:
314    # if nc-config exists, and USE_NCCONFIG not set, try to use it.
315    if HAS_NCCONFIG: USE_NCCONFIG=True
316#elif USE_NCCONFIG is None:
317#    USE_NCCONFIG = False # don't try to use nc-config if USE_NCCONFIG not set
318
319try:
320    HAS_PKG_CONFIG = subprocess.call(['pkg-config', '--libs', 'hdf5'],
321                                     stdout=subprocess.PIPE) == 0
322except OSError:
323    HAS_PKG_CONFIG = False
324
325def _populate_hdf5_info(dirstosearch, inc_dirs, libs, lib_dirs):
326    global HDF5_incdir, HDF5_dir, HDF5_libdir
327
328    nohdf5dirs = HDF5_incdir is None and HDF5_libdir is None and  HDF5_dir is None
329    if HAS_PKG_CONFIG and nohdf5dirs:
330        # if HDF5 dirs not specified, and pkg-config available, use it
331        dep = subprocess.Popen(['pkg-config', '--cflags', 'hdf5'],
332                               stdout=subprocess.PIPE).communicate()[0]
333        inc_dirs.extend([str(i[2:].decode()) for i in dep.split() if
334                         i[0:2].decode() == '-I'])
335        dep = subprocess.Popen(['pkg-config', '--libs', 'hdf5'],
336                               stdout=subprocess.PIPE).communicate()[0]
337        libs.extend(
338            [str(l[2:].decode()) for l in dep.split() if l[0:2].decode() == '-l'])
339        lib_dirs.extend(
340            [str(l[2:].decode()) for l in dep.split() if l[0:2].decode() == '-L'])
341        dep = subprocess.Popen(['pkg-config', '--cflags', 'hdf5'],
342                               stdout=subprocess.PIPE).communicate()[0]
343        inc_dirs.extend(
344            [str(i[2:].decode()) for i in dep.split() if i[0:2].decode() == '-I'])
345    else:
346        if HDF5_incdir is None and HDF5_dir is None:
347            sys.stdout.write("""
348    HDF5_DIR environment variable not set, checking some standard locations ..\n""")
349            for direc in dirstosearch:
350                hdf5_version = get_hdf5_version(os.path.join(direc, 'include'))
351                if hdf5_version is None:
352                    continue
353                else:
354                    HDF5_dir = direc
355                    HDF5_incdir = os.path.join(direc, 'include')
356                    sys.stdout.write('%s found in %s\n' %
357                                    (hdf5_version,HDF5_dir))
358                    break
359            if HDF5_dir is None:
360                raise ValueError('did not find HDF5 headers')
361        else:
362            if HDF5_incdir is None:
363                HDF5_incdir = os.path.join(HDF5_dir, 'include')
364            hdf5_version = get_hdf5_version(HDF5_incdir)
365            if hdf5_version is None:
366                raise ValueError('did not find HDF5 headers in %s' % HDF5_incdir)
367            else:
368                sys.stdout.write('%s found in %s\n' %
369                                (hdf5_version,HDF5_dir))
370
371        if HDF5_libdir is None and HDF5_dir is not None:
372            HDF5_libdir = os.path.join(HDF5_dir, 'lib')
373
374        if HDF5_libdir is not None: lib_dirs.append(HDF5_libdir)
375        if HDF5_incdir is not None: inc_dirs.append(HDF5_incdir)
376
377        libs.extend(['hdf5_hl', 'hdf5'])
378
379
380dirstosearch = []
381if os.environ.get("CONDA_PREFIX"):
382    dirstosearch.append(os.environ["CONDA_PREFIX"]) # linux,macosx
383    dirstosearch.append(os.path.join(os.environ["CONDA_PREFIX"],'Library')) # windows
384dirstosearch += [os.path.expanduser('~'), '/usr/local', '/sw', '/opt',
385                '/opt/local', '/usr']
386
387# try nc-config first
388if USE_NCCONFIG and HAS_NCCONFIG:  # Try nc-config.
389    sys.stdout.write('using %s...\n' % ncconfig)
390    dep = subprocess.Popen([ncconfig, '--libs'],
391                           stdout=subprocess.PIPE).communicate()[0]
392    libs = [str(l[2:].decode()) for l in dep.split() if l[0:2].decode() == '-l']
393    lib_dirs = [str(l[2:].decode()) for l in dep.split() if
394                l[0:2].decode() == '-L']
395    dep = subprocess.Popen([ncconfig, '--cflags'],
396                           stdout=subprocess.PIPE).communicate()[0]
397    inc_dirs = [str(i[2:].decode()) for i in dep.split() if
398                i[0:2].decode() == '-I']
399
400    # check to see if hdf5 found in directories returned by nc-config
401    hdf5_version = None
402    for direc in inc_dirs:
403        hdf5_version = get_hdf5_version(direc)
404        if hdf5_version is not None:
405            break
406    # if hdf5 not found, search other standard locations (including those specified in env vars).
407    if hdf5_version is None:
408        sys.stdout.write('nc-config did provide path to HDF5 headers, search standard locations...')
409        _populate_hdf5_info(dirstosearch, inc_dirs, libs, lib_dirs)
410
411# If nc-config doesn't work, fall back on brute force method.
412else:
413    lib_dirs = []
414    inc_dirs = []
415    libs = []
416
417    # _populate_hdf5_info will use HDF5_dir, HDF5_libdir and HDF5_incdir if they are set.
418    # otherwise pkg-config will be tried, and if that fails, dirstosearch will be searched.
419    _populate_hdf5_info(dirstosearch, inc_dirs, libs, lib_dirs)
420
421    if netCDF4_incdir is None and netCDF4_dir is None:
422        sys.stdout.write("""
423NETCDF4_DIR environment variable not set, checking standard locations.. \n""")
424        for direc in dirstosearch:
425            sys.stdout.write('checking %s ...\n' % direc)
426            isnetcdf4 = check_ifnetcdf4(os.path.join(direc, 'include'))
427            if not isnetcdf4:
428                continue
429            else:
430                netCDF4_dir = direc
431                netCDF4_incdir = os.path.join(direc, 'include')
432                sys.stdout.write('netCDF4 found in %s\n' % netCDF4_dir)
433                break
434        if netCDF4_dir is None:
435            raise ValueError('did not find netCDF version 4 headers')
436    else:
437        if netCDF4_incdir is None:
438            netCDF4_incdir = os.path.join(netCDF4_dir, 'include')
439        isnetcdf4 = check_ifnetcdf4(netCDF4_incdir)
440        if not isnetcdf4:
441            raise ValueError(
442                'did not find netCDF version 4 headers %s' % netCDF4_incdir)
443
444    if netCDF4_libdir is None and netCDF4_dir is not None:
445        netCDF4_libdir = os.path.join(netCDF4_dir, 'lib')
446
447    if sys.platform == 'win32':
448        libs.extend(['netcdf', 'zlib'])
449    else:
450        libs.extend(['netcdf', 'z'])
451
452    if netCDF4_libdir is not None: lib_dirs.append(netCDF4_libdir)
453    if netCDF4_incdir is not None: inc_dirs.append(netCDF4_incdir)
454
455    # add szip to link if desired.
456    if szip_libdir is None and szip_dir is not None:
457        szip_libdir = os.path.join(szip_dir, 'lib')
458    if szip_incdir is None and szip_dir is not None:
459        szip_incdir = os.path.join(szip_dir, 'include')
460    if szip_incdir is not None and szip_libdir is not None:
461        libs.append('sz')
462        lib_dirs.append(szip_libdir)
463        inc_dirs.append(szip_incdir)
464    # add hdf4 to link if desired.
465    if hdf4_libdir is None and hdf4_dir is not None:
466        hdf4_libdir = os.path.join(hdf4_dir, 'lib')
467    if hdf4_incdir is None and hdf4_dir is not None:
468        hdf4_incdir = os.path.join(hdf4_dir, 'include')
469    if hdf4_incdir is not None and hdf4_libdir is not None:
470        libs.append('mfhdf')
471        libs.append('df')
472        lib_dirs.append(hdf4_libdir)
473        inc_dirs.append(hdf4_incdir)
474    # add jpeg to link if desired.
475    if jpeg_libdir is None and jpeg_dir is not None:
476        jpeg_libdir = os.path.join(jpeg_dir, 'lib')
477    if jpeg_incdir is None and jpeg_dir is not None:
478        jpeg_incdir = os.path.join(jpeg_dir, 'include')
479    if jpeg_incdir is not None and jpeg_libdir is not None:
480        libs.append('jpeg')
481        lib_dirs.append(jpeg_libdir)
482        inc_dirs.append(jpeg_incdir)
483    # add curl to link if desired.
484    if curl_libdir is None and curl_dir is not None:
485        curl_libdir = os.path.join(curl_dir, 'lib')
486    if curl_incdir is None and curl_dir is not None:
487        curl_incdir = os.path.join(curl_dir, 'include')
488    if curl_incdir is not None and curl_libdir is not None:
489        libs.append('curl')
490        lib_dirs.append(curl_libdir)
491        inc_dirs.append(curl_incdir)
492
493if sys.platform == 'win32':
494    runtime_lib_dirs = []
495else:
496    runtime_lib_dirs = lib_dirs
497
498# Do not require numpy for just querying the package
499# Taken from the h5py setup file.
500if any('--' + opt in sys.argv for opt in Distribution.display_option_names +
501        ['help-commands', 'help']) or sys.argv[1] == 'egg_info':
502    pass
503else:
504    # append numpy include dir.
505    import numpy
506    inc_dirs.append(numpy.get_include())
507
508# get netcdf library version.
509netcdf_lib_version = getnetcdfvers(lib_dirs)
510if netcdf_lib_version is None:
511    sys.stdout.write('unable to detect netcdf library version\n')
512else:
513    netcdf_lib_version = str(netcdf_lib_version)
514    sys.stdout.write('using netcdf library version %s\n' % netcdf_lib_version)
515
516cmdclass = {}
517DEFINE_MACROS = [("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")]
518netcdf4_src_root = osp.join(osp.join('src','netCDF4'), '_netCDF4')
519netcdf4_src_c = netcdf4_src_root + '.c'
520netcdf4_src_pyx = netcdf4_src_root + '.pyx'
521if 'sdist' not in sys.argv[1:] and 'clean' not in sys.argv[1:] and '--version' not in sys.argv[1:]:
522    sys.stdout.write('using Cython to compile netCDF4.pyx...\n')
523    # remove _netCDF4.c file if it exists, so cython will recompile _netCDF4.pyx.
524    # run for build *and* install (issue #263). Otherwise 'pip install' will
525    # not regenerate _netCDF4.c, even if the C lib supports the new features.
526    if len(sys.argv) >= 2:
527        if os.path.exists(netcdf4_src_c):
528            os.remove(netcdf4_src_c)
529    # this determines whether renameGroup and filepath methods will work.
530    has_rename_grp, has_nc_inq_path, has_nc_inq_format_extended, \
531    has_cdf5_format, has_nc_open_mem, has_nc_create_mem, \
532    has_parallel4_support, has_pnetcdf_support = \
533    check_api(inc_dirs,netcdf_lib_version)
534    # for netcdf 4.4.x CDF5 format is always enabled.
535    if netcdf_lib_version is not None and\
536       (netcdf_lib_version > "4.4" and netcdf_lib_version < "4.5"):
537        has_cdf5_format = True
538
539    # disable parallel support if mpi4py not available.
540    try:
541        import mpi4py
542    except ImportError:
543        has_parallel4_support = False
544        has_pnetcdf_support = False
545
546    f = open(osp.join('include', 'constants.pyx'), 'w')
547    if has_rename_grp:
548        sys.stdout.write('netcdf lib has group rename capability\n')
549        f.write('DEF HAS_RENAME_GRP = 1\n')
550    else:
551        sys.stdout.write('netcdf lib does not have group rename capability\n')
552        f.write('DEF HAS_RENAME_GRP = 0\n')
553
554    if has_nc_inq_path:
555        sys.stdout.write('netcdf lib has nc_inq_path function\n')
556        f.write('DEF HAS_NC_INQ_PATH = 1\n')
557    else:
558        sys.stdout.write('netcdf lib does not have nc_inq_path function\n')
559        f.write('DEF HAS_NC_INQ_PATH = 0\n')
560
561    if has_nc_inq_format_extended:
562        sys.stdout.write('netcdf lib has nc_inq_format_extended function\n')
563        f.write('DEF HAS_NC_INQ_FORMAT_EXTENDED = 1\n')
564    else:
565        sys.stdout.write(
566            'netcdf lib does not have nc_inq_format_extended function\n')
567        f.write('DEF HAS_NC_INQ_FORMAT_EXTENDED = 0\n')
568
569    if has_nc_open_mem:
570        sys.stdout.write('netcdf lib has nc_open_mem function\n')
571        f.write('DEF HAS_NC_OPEN_MEM = 1\n')
572    else:
573        sys.stdout.write('netcdf lib does not have nc_open_mem function\n')
574        f.write('DEF HAS_NC_OPEN_MEM = 0\n')
575
576    if has_nc_create_mem:
577        sys.stdout.write('netcdf lib has nc_create_mem function\n')
578        f.write('DEF HAS_NC_CREATE_MEM = 1\n')
579    else:
580        sys.stdout.write('netcdf lib does not have nc_create_mem function\n')
581        f.write('DEF HAS_NC_CREATE_MEM = 0\n')
582
583    if has_cdf5_format:
584        sys.stdout.write('netcdf lib has cdf-5 format capability\n')
585        f.write('DEF HAS_CDF5_FORMAT = 1\n')
586    else:
587        sys.stdout.write('netcdf lib does not have cdf-5 format capability\n')
588        f.write('DEF HAS_CDF5_FORMAT = 0\n')
589
590    if has_parallel4_support:
591        sys.stdout.write('netcdf lib has netcdf4 parallel functions\n')
592        f.write('DEF HAS_PARALLEL4_SUPPORT = 1\n')
593    else:
594        sys.stdout.write('netcdf lib does not have netcdf4 parallel functions\n')
595        f.write('DEF HAS_PARALLEL4_SUPPORT = 0\n')
596
597    if has_pnetcdf_support:
598        sys.stdout.write('netcdf lib has pnetcdf parallel functions\n')
599        f.write('DEF HAS_PNETCDF_SUPPORT = 1\n')
600    else:
601        sys.stdout.write('netcdf lib does not have pnetcdf parallel functions\n')
602        f.write('DEF HAS_PNETCDF_SUPPORT = 0\n')
603
604    f.close()
605
606    if has_parallel4_support or has_pnetcdf_support:
607        inc_dirs.append(mpi4py.get_include())
608        # mpi_incdir should not be needed if using nc-config
609        # (should be included in nc-config --cflags)
610        if mpi_incdir is not None: inc_dirs.append(mpi_incdir)
611
612    ext_modules = [Extension("netCDF4._netCDF4",
613                             [netcdf4_src_pyx],
614                             define_macros=DEFINE_MACROS,
615                             libraries=libs,
616                             library_dirs=lib_dirs,
617                             include_dirs=inc_dirs + ['include'],
618                             runtime_library_dirs=runtime_lib_dirs)]
619else:
620    ext_modules = None
621
622setup(name="netCDF4",
623      cmdclass=cmdclass,
624      version=extract_version(netcdf4_src_pyx),
625      long_description="netCDF version 4 has many features not found in earlier versions of the library, such as hierarchical groups, zlib compression, multiple unlimited dimensions, and new data types.  It is implemented on top of HDF5.  This module implements most of the new features, and can read and write netCDF files compatible with older versions of the library.  The API is modelled after Scientific.IO.NetCDF, and should be familiar to users of that module.\n\nThis project is hosted on a `GitHub repository <https://github.com/Unidata/netcdf4-python>`_ where you may access the most up-to-date source.",
626      author="Jeff Whitaker",
627      author_email="jeffrey.s.whitaker@noaa.gov",
628      url="http://github.com/Unidata/netcdf4-python",
629      download_url="http://python.org/pypi/netCDF4",
630      platforms=["any"],
631      license='License :: OSI Approved :: MIT License',
632      description="Provides an object-oriented python interface to the netCDF version 4 library.",
633      keywords=['numpy', 'netcdf', 'data', 'science', 'network', 'oceanography',
634                'meteorology', 'climate'],
635      classifiers=["Development Status :: 3 - Alpha",
636                   "Programming Language :: Python :: 3",
637                   "Programming Language :: Python :: 3.6",
638                   "Programming Language :: Python :: 3.7",
639                   "Programming Language :: Python :: 3.8",
640                   "Intended Audience :: Science/Research",
641                   "License :: OSI Approved :: MIT License",
642                   "Topic :: Software Development :: Libraries :: Python Modules",
643                   "Topic :: System :: Archiving :: Compression",
644                   "Operating System :: OS Independent"],
645      packages=['netCDF4'],
646      package_dir={'':'src'},
647      ext_modules=ext_modules,
648      **setuptools_extra_kwargs)
649