diff --git a/AUTHORS.rst b/AUTHORS.rst index db81602b..bb740b39 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -24,3 +24,4 @@ Contributors * Suhas D L * Abel Shibu * Monali Vadje +* Takeshi Enomoto diff --git a/HISTORY.rst b/HISTORY.rst index 757d585e..4b24ab6c 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -2,6 +2,11 @@ History ======= +v.0.16.26 +--------- + +* Add support for build with OpenBLAS and FFTW-3 installed by MacPorts or FreeBSD pkg/ports + v.0.16.11 --------- diff --git a/climt/_lib/FreeBSD/.temp b/climt/_lib/FreeBSD/.temp new file mode 100644 index 00000000..e69de29b diff --git a/climt/_lib/Makefile b/climt/_lib/Makefile index 94706c65..7d70064b 100644 --- a/climt/_lib/Makefile +++ b/climt/_lib/Makefile @@ -18,7 +18,7 @@ CLIMT_FFTW_FLAGS = --enable-openmp --enable-avx --enable-avx2 LIB_DIR= $(BASE_DIR)/$(CLIMT_ARCH)/ CLIMT_CFLAGS = "-I$(BASE_DIR) -L$(LIB_DIR) $(CFLAGS)" -LDFLAGS = "-L$(LIB_DIR)" +CLIMT_LDFLAGS = "-L$(LIB_DIR) $(LDFLAGS)" CLIMT_LIB_TARGETS = blas_lib fftw_lib @@ -28,6 +28,9 @@ ifeq ($(CLIMT_ARCH),Windows) CLIMT_FFTW_FLAGS = --with-our-malloc --build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --enable-static --with-g77-wrappers --with-windows-f77-mangling --enable-sse2 --enable-avx CLIMT_LIB_TARGETS = endif +ifeq ($(USE_SYSTEM_LIBS),1) + CLIMT_LIB_TARGETS = +endif all: $(CLIMT_LIB_TARGETS) sht_lib gfs_lib simple_physics_lib emanuel_lib rrtmg_lw_lib rrtmg_sw_lib libdcmip @@ -35,10 +38,10 @@ all: $(CLIMT_LIB_TARGETS) sht_lib gfs_lib simple_physics_lib emanuel_lib rrtmg_l # FFTW3 Configuration $(CLIMT_ARCH)/.configured_fftw: - if [ ! -d $(FFTW_DIR) ]; then tar -xvzf $(FFTW_GZ) > log 2>&1; fi; cd $(FFTW_DIR); ./configure CFLAGS=$(CLIMT_CFLAGS) LDFLAGS=$(LDFLAGS) --prefix="$(BASE_DIR)" $(CLIMT_FFTW_FLAGS) > log.config.fftw 2>&1 && touch ../$(CLIMT_ARCH)/.configured_fftw + if [ ! -d $(FFTW_DIR) ]; then tar -xvzf $(FFTW_GZ) > log 2>&1; fi; cd $(FFTW_DIR); ./configure CFLAGS=$(CLIMT_CFLAGS) LDFLAGS=$(CLIMT_LDFLAGS) --prefix="$(BASE_DIR)" $(CLIMT_FFTW_FLAGS) > log.config.fftw 2>&1 && touch ../$(CLIMT_ARCH)/.configured_fftw $(CLIMT_ARCH)/libfftw3_omp.a: $(CLIMT_ARCH)/.configured_fftw - cd $(FFTW_DIR); make install > log.install.fftw 2>&1; cp ../lib/libfftw3_omp.a $(LIB_DIR) + cd $(FFTW_DIR); $(MAKE) install > log.install.fftw 2>&1; cp ../lib/libfftw3_omp.a $(LIB_DIR) $(CLIMT_ARCH)/libfftw3.a: $(CLIMT_ARCH)/.configured_fftw cp lib/libfftw3.a $(LIB_DIR) @@ -49,10 +52,10 @@ fftw_lib: $(CLIMT_ARCH)/libfftw3_omp.a $(CLIMT_ARCH)/libfftw3.a # SHTNS Configuration $(CLIMT_ARCH)/.configured_sht: - if [ ! -d $(SHT_DIR) ]; then tar -xvzf $(SHT_GZ) ; fi; cd $(SHT_DIR); ./configure CFLAGS=$(CLIMT_CFLAGS) LDFLAGS=$(LDFLAGS) --prefix=$(BASE_DIR) --disable-python --enable-openmp && touch ../$(CLIMT_ARCH)/.configured_sht + if [ ! -d $(SHT_DIR) ]; then tar -xvzf $(SHT_GZ) ; fi; cd $(SHT_DIR); ./configure CFLAGS=$(CLIMT_CFLAGS) LDFLAGS=$(CLIMT_LDFLAGS) --prefix=$(BASE_DIR) --disable-python --enable-openmp && touch ../$(CLIMT_ARCH)/.configured_sht $(CLIMT_ARCH)/libshtns_omp.a: $(CLIMT_ARCH)/.configured_sht - cd $(SHT_DIR); make install > log 2>&1; cat log; cp ../lib/libshtns_omp.a $(LIB_DIR); ls -ltrh $(LIB_DIR) + cd $(SHT_DIR); $(MAKE) install > log 2>&1; cat log; cp ../lib/libshtns_omp.a $(LIB_DIR); ls -ltrh $(LIB_DIR) sht_lib: $(CLIMT_ARCH)/libshtns_omp.a @@ -61,49 +64,49 @@ sht_lib: $(CLIMT_ARCH)/libshtns_omp.a blas_lib: $(CLIMT_ARCH)/libopenblas.a $(CLIMT_ARCH)/libopenblas.a: - if [ ! -d $(BLAS_DIR) ]; then tar -xvzf $(BLAS_GZ) > log 2>&1; fi; cd $(BLAS_DIR); CFLAGS=$(CLIMT_CFLAGS) make NO_SHARED=1 NO_LAPACK=0 > log 2>&1 ; make PREFIX=$(BASE_DIR) NO_SHARED=1 NO_LAPACK=0 install > log.install.blas 2>&1 ; cp ../lib/libopenblas.a $(LIB_DIR) + if [ ! -d $(BLAS_DIR) ]; then tar -xvzf $(BLAS_GZ) > log 2>&1; fi; cd $(BLAS_DIR); CFLAGS=$(CLIMT_CFLAGS) $(MAKE) NO_SHARED=1 NO_LAPACK=0 > log 2>&1 ; $(MAKE) PREFIX=$(BASE_DIR) NO_SHARED=1 NO_LAPACK=0 install > log.install.blas 2>&1 ; cp ../lib/libopenblas.a $(LIB_DIR) # GFS Configuration gfs_lib: $(CLIMT_ARCH)/libgfs_dycore.a $(CLIMT_ARCH)/libgfs_dycore.a: $(GFS_DIR)/*.f90 - cd $(GFS_DIR); make python_lib; cp libgfs_dycore.a $(LIB_DIR); touch ../../_components/gfs/_gfs_dynamics.pyx + cd $(GFS_DIR); $(MAKE) python_lib; cp libgfs_dycore.a $(LIB_DIR); touch ../../_components/gfs/_gfs_dynamics.pyx # Simple Physics Configuration simple_physics_lib: $(CLIMT_ARCH)/libsimple_physics.a $(CLIMT_ARCH)/libsimple_physics.a: $(SIM_PHYS_DIR)/*.f90 - cd $(SIM_PHYS_DIR); make; cp libsimple_physics.a $(LIB_DIR); touch ../../_components/simple_physics/_simple_physics.pyx + cd $(SIM_PHYS_DIR); $(MAKE); cp libsimple_physics.a $(LIB_DIR); touch ../../_components/simple_physics/_simple_physics.pyx # Emanuel Convection Configuration emanuel_lib: $(CLIMT_ARCH)/libemanuel.a $(CLIMT_ARCH)/libemanuel.a: $(EMAN_DIR)/*.f90 - cd $(EMAN_DIR); make; cp libemanuel.a $(LIB_DIR); touch ../../_components/emanuel/_emanuel_convection.pyx + cd $(EMAN_DIR); $(MAKE); cp libemanuel.a $(LIB_DIR); touch ../../_components/emanuel/_emanuel_convection.pyx # RRTMG LW Configuration rrtmg_lw_lib: $(CLIMT_ARCH)/librrtmg_lw.a $(CLIMT_ARCH)/librrtmg_lw.a: $(RRTMG_LW_DIR)/*.f90 - cd $(RRTMG_LW_DIR); make; cp librrtmg_lw.a $(LIB_DIR); touch ../../_components/rrtmg/lw/_rrtmg_lw.pyx + cd $(RRTMG_LW_DIR); $(MAKE); cp librrtmg_lw.a $(LIB_DIR); touch ../../_components/rrtmg/lw/_rrtmg_lw.pyx # RRTMG SW Configuration rrtmg_sw_lib: $(CLIMT_ARCH)/librrtmg_sw.a $(CLIMT_ARCH)/librrtmg_sw.a: $(RRTMG_SW_DIR)/*.f90 - cd $(RRTMG_SW_DIR); make; cp librrtmg_sw.a $(LIB_DIR); touch ../../_components/rrtmg/sw/_rrtmg_sw.pyx + cd $(RRTMG_SW_DIR); $(MAKE); cp librrtmg_sw.a $(LIB_DIR); touch ../../_components/rrtmg/sw/_rrtmg_sw.pyx # DCMIP Configuration libdcmip: $(CLIMT_ARCH)/libdcmip.a $(CLIMT_ARCH)/libdcmip.a: $(DCMIP_DIR)/*.f90 - cd $(DCMIP_DIR); make; cp libdcmip.a $(LIB_DIR); touch ../../_components/dcmip/_dcmip.pyx + cd $(DCMIP_DIR); $(MAKE); cp libdcmip.a $(LIB_DIR); touch ../../_components/dcmip/_dcmip.pyx @@ -111,12 +114,12 @@ clean: if [ -d $(FFTW_DIR) ]; then rm -Rf $(FFTW_DIR); fi if [ -d $(SHT_DIR) ]; then rm -Rf $(SHT_DIR); fi if [ -d $(BLAS_DIR) ]; then rm -Rf $(BLAS_DIR); fi - cd $(GFS_DIR); make clean - cd $(SIM_PHYS_DIR); make clean - cd $(EMAN_DIR); make clean - cd $(RRTMG_LW_DIR); make clean - cd $(RRTMG_SW_DIR); make clean - cd $(DCMIP_DIR); make clean + cd $(GFS_DIR); $(MAKE) clean + cd $(SIM_PHYS_DIR); $(MAKE) clean + cd $(EMAN_DIR); $(MAKE) clean + cd $(RRTMG_LW_DIR); $(MAKE) clean + cd $(RRTMG_SW_DIR); $(MAKE) clean + cd $(DCMIP_DIR); $(MAKE) clean clean_libs: if [ -d include ]; then rm -Rf include; fi diff --git a/setup.py b/setup.py index ada85ab2..4392cf82 100644 --- a/setup.py +++ b/setup.py @@ -55,6 +55,25 @@ def find_homebrew_gcc(): return glob.glob('/usr/local/Cellar/gcc*')[0] +def find_macports_gcc(gcc, prefix='/opt/local'): + candidate = os.path.join(prefix, 'bin', gcc) + if os.path.exists(candidate): + return candidate + else: + candidates = glob.glob(candidate + '-mp-*') + if len(candidates) == 0: + print(f"{gcc} does not exist in {prefix}") + sys.exit() + else: + return candidates[-1] # return latest + +def find_freebsd_gcc(gcc, prefix='/usr/local'): + candidates = glob.glob(os.path.join(prefix, 'bin', gcc) + '[0-9]*') + if len(candidates) == 0: + print(f"{gcc} does not exist in {prefix}") + sys.exit() + else: + return candidates[-1] # return latest # Platform specific settings def guess_compiler_name(env_name): @@ -95,15 +114,55 @@ def guess_compiler_name(env_name): inc_path = os.path.join(compiled_path, 'include') include_dirs.append(inc_path) openblas_path = lib_path_list[0]+'/libopenblas.a' - +fftw3_omp_path = lib_path_list[0]+'/libfftw3_omp.a', +fftw3_path = lib_path_list[0]+'/libfftw3.a', # Compile libraries +if operating_system == 'Darwin': + if 'MACPORTS_PREFIX' not in os.environ: + macports_prefix = '/opt/local' + if os.path.exists(macports_prefix): + os.environ['USE_SYSTEM_LIBS'] = '1' + os.environ['CFLAGS'] = f'-I{macports_prefix}/include' + os.environ['LDFLAGS'] = f'-L{macports_prefix}/lib' + lib_path_list.append(os.path.join(macports_prefix, 'lib')) + openblas_path = os.path.join(lib_path_list[-1], 'libopenblas.a') + fftw3_omp_path = os.path.join(lib_path_list[-1], 'libfftw3_omp.a') + fftw3_path = os.path.join(lib_path_list[-1], 'libfftw3.a') +elif operating_system == 'FreeBSD': + ports_prefix = '/usr/local' + if os.path.exists(ports_prefix): + os.environ['USE_SYSTEM_LIBS'] = '1' + os.environ['CFLAGS'] = f'-I{ports_prefix}/include' + os.environ['LDFLAGS'] = f'-L{ports_prefix}/lib' + lib_path_list.append(os.path.join(ports_prefix, 'lib')) + openblas_path = os.path.join(lib_path_list[-1], 'libopenblas.so') + fftw3_omp_path = os.path.join(lib_path_list[-1], 'libfftw3_omp.so') + fftw3_path = os.path.join(lib_path_list[-1], 'libfftw3.so') +elif operating_system == 'Windows' : + os.environ['CC'] = 'gcc.exe' + os.environ['FC'] = 'gfortran.exe' + os.environ['AR'] = 'gcc-ar.exe' + libraries = [] + openblas_path = os.path.join(os.environ['COMPILER_PATH'], '../lib/libopenblas.a') + default_link_args = ['-l:libgfortran.a', '-l:libquadmath.a', '-l:libm.a'] + default_compile_args = ['-DMS_WIN64'] + if 'FC' not in os.environ: if operating_system == 'Darwin': # guess_compiler_name('FC') - os.environ['FC'] = 'gfortran-6' - os.environ['F77'] = 'gfortran-6' + if os.path.exists(macports_prefix): + fc = find_macports_gcc('gfortran', macports_prefix) + os.environ['FC'] = fc + os.environ['F77'] = fc + else: + os.environ['FC'] = 'gfortran-6' + os.environ['F77'] = 'gfortran-6' + elif operating_system == 'FreeBSD': + fc = find_freebsd_gcc('gfortran', ports_prefix) + os.environ['FC'] = fc + os.environ['F77'] = fc else: os.environ['FC'] = 'gfortran' os.environ['F77'] = 'gfortran' @@ -111,37 +170,47 @@ def guess_compiler_name(env_name): if 'CC' not in os.environ: if operating_system == 'Darwin': # guess_compiler_name('CC') - os.environ['CC'] = 'gcc-6' + if os.path.exists(macports_prefix): + os.environ['CC'] = find_macports_gcc('gcc', macports_prefix) + else: + os.environ['CC'] = 'gcc-6' + elif operating_system == 'FreeBSD': + os.environ['CC'] = find_freebsd_gcc('gcc', ports_prefix) else: os.environ['CC'] = 'gcc' if 'CLIMT_OPT_FLAGS' not in os.environ: os.environ['CLIMT_OPT_FLAGS'] = '-O3' -if operating_system == 'Windows' : - os.environ['CC'] = 'gcc.exe' - os.environ['FC'] = 'gfortran.exe' - os.environ['AR'] = 'gcc-ar.exe' - libraries = [] - openblas_path = os.path.join(os.environ['COMPILER_PATH'], '../lib/libopenblas.a') - default_link_args = ['-l:libgfortran.a', '-l:libquadmath.a', '-l:libm.a'] - default_compile_args = ['-DMS_WIN64'] - os.environ['FFLAGS'] = '-fPIC -fno-range-check ' + os.environ['CLIMT_OPT_FLAGS'] -os.environ['CFLAGS'] = '-fPIC ' + os.environ['CLIMT_OPT_FLAGS'] +os.environ['CFLAGS'] += ' -fPIC ' + os.environ['CLIMT_OPT_FLAGS'] + +gcc_major = subprocess.check_output( + '${CC} -dumpversion', shell=True).decode().strip().split('.')[0] +gfortran_major = subprocess.check_output( + '${FC} -dumpversion', shell=True).decode().strip().split('.')[0] +if int(gfortran_major) > 9: + os.environ['FFLAGS'] += ' -fno-range-check -std=legacy -fallow-argument-mismatch' if operating_system == 'Darwin': - gcc_dir = find_homebrew_gcc() - for root, dirs, files in os.walk(gcc_dir): - for line in files: - if re.match('libgfortran.a', line): - if not ('i386' in root): - lib_path_list.append(root) + if os.path.exists(macports_prefix): + gcc_dir = glob.glob(os.path.join(lib_path_list[-1], 'gcc*'))[0] + lib_path_list.append(gcc_dir) + default_link_args = ['-Wl,-rpath,'+ gcc_dir] + else: + gcc_dir = find_homebrew_gcc() + for root, dirs, files in os.walk(gcc_dir): + for line in files: + if re.match('libgfortran.a', line): + if not ('i386' in root): + lib_path_list.append(root) + default_link_args = [] os.environ['FFLAGS'] += ' -mmacosx-version-min=10.7' os.environ['CFLAGS'] += ' -mmacosx-version-min=10.7' - default_link_args = [] - os.environ['LDSHARED'] = os.environ['CC']+' -bundle -undefined dynamic_lookup -arch x86_64' + os.environ['LDSHARED'] = os.environ['CC']+' -bundle -undefined dynamic_lookup -march=native' +elif operating_system == 'FreeBSD': + lib_path_list.append(os.path.join(ports_prefix, 'lib', 'gcc'+gcc_major)) print('Compilers: ', os.environ['CC'], os.environ['FC']) @@ -155,7 +224,12 @@ def build_libraries(): curr_dir = os.getcwd() os.chdir(compiled_path) os.environ['PWD'] = compiled_path - if subprocess.call(['make', 'CLIMT_ARCH='+operating_system]): + + if operating_system == 'FreeBSD': + make = 'gmake' + else: + make = 'make' + if subprocess.call([make, 'CLIMT_ARCH='+operating_system]): raise RuntimeError('Library build failed, exiting') os.chdir(curr_dir) os.environ['PWD'] = curr_dir @@ -222,8 +296,8 @@ def run(self): extra_compile_args=['-fopenmp'] + default_compile_args, library_dirs=lib_path_list, extra_link_args=['-fopenmp', lib_path_list[0]+'/libgfs_dycore.a', - lib_path_list[0]+'/libshtns_omp.a', lib_path_list[0]+'/libfftw3_omp.a', - lib_path_list[0]+'/libfftw3.a', openblas_path] + default_link_args), + lib_path_list[0]+'/libshtns_omp.a', fftw3_omp_path, + fftw3_path, openblas_path] + default_link_args), # lib_path+'/libshtns_omp.a', openblas_path, os.environ['COMPILER_PATH']+'../lib/libfftw3.a'] + default_link_args),