8000 add modifications to handle gfortran on msvc · Pull Request #9429 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

add modifications to handle gfortran on msvc #9429

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 118 additions & 38 deletions numpy/distutils/command/build_clib.py
10000
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,26 @@
import os
from glob import glob
import shutil
from copy import copy
from distutils.command.build_clib import build_clib as old_build_clib
from distutils._msvccompiler import MSVCCompiler, _find_exe
from distutils.errors import DistutilsSetupError, DistutilsError, \
DistutilsFileError
DistutilsFileError

from numpy.distutils import log
from distutils.dep_util import newer_group
from numpy.distutils.misc_util import filter_sources, has_f_sources,\
has_cxx_sources, all_strings, get_lib_source_files, is_sequence, \
get_numpy_include_dirs
has_cxx_sources, all_strings, get_lib_source_files, is_sequence, \
get_numpy_include_dirs

# Fix Python distutils bug sf #1718574:
_l = old_build_clib.user_options
for _i in range(len(_l)):
if _l[_i][0] in ['build-clib', 'build-temp']:
_l[_i] = (_l[_i][0]+'=',)+_l[_i][1:]
_l[_i] = (_l[_i][0] + '=',) + _l[_i][1:]
#


class build_clib(old_build_clib):

description = "build C/C++/F libraries used by Python extensions"
Expand All @@ -32,7 +35,7 @@ class build_clib(old_build_clib):
('inplace', 'i', 'Build in-place'),
('parallel=', 'j',
"number of parallel jobs"),
]
]

boolean_options = old_build_clib.boolean_options + ['inplace']

Expand All @@ -41,6 +44,8 @@ def initialize_options(self):
self.fcompiler = None
self.inplace = 0
self.parallel = None
self.dlls = [
'C:\\projects\\build-scipy\\venv\\Lib\\site-packages\\numpy\\core\\libopenblas_v0.2.19_mingwpy.dll']

def finalize_options(self):
if self.parallel:
Expand Down Expand Up @@ -75,7 +80,8 @@ def run(self):

for (lib_name, build_info) in self.libraries:
l = build_info.get('language', None)
if l and l not in languages: languages.append(l)
if l and l not in languages:
languages.append(l)

from distutils.ccompiler import new_compiler
self.compiler = new_compiler(compiler=self.compiler,
Expand All @@ -94,11 +100,11 @@ def run(self):
if self.have_f_sources():
from numpy.distutils.fcompiler import new_fcompiler
self._f_compiler = new_fcompiler(compiler=self.fcompiler,
verbose=self.verbose,
dry_run=self.dry_run,
force=self.force,
requiref90='f90' in languages,
c_compiler=self.compiler)
verbose=self.verbose,
dry_run=self.dry_run,
force=self.force,
requiref90='f90' in languages,
c_compiler=self.compiler)
if self._f_compiler is not None:
self._f_compiler.customize(self.distribution)

Expand All @@ -114,10 +120,10 @@ def run(self):
self.build_libraries(self.libraries)

if self.inplace:
for l in self.distribution.installed_libraries:
for l in self.distribution.installed_libraries:
libname = self.compiler.library_filename(l.name)
source = os.path.join(self.build_clib, libname)
target = os.path.join(l.target_dir, libname)
target = os.path.join(l.target_dir, libname)
self.mkpath(l.target_dir)
shutil.copy(source, target)

Expand All @@ -129,8 +135,37 @@ def get_source_files(self):
return filenames

def build_libraries(self, libraries):
library_names = [
'mach',
'dfftpack',
'fftpack',
'sc_mach',
'sc_amos',
'sc_cdf',
'sc_specfun',
'statlib',
'quadpack',
'dop',
'fitpack',
'fwrappers',
'odrpack',
'minpack',
'arpack_scipy',
'odepack',
'rootfind',
'superlu_src',
'sc_c_misc',
'sc_cephes',
]

for lib_name in library_names:
self.build_specific_library(libraries, lib_name)

def build_specific_library(self, libraries, library_name):
for (lib_name, build_info) in libraries:
self.build_a_library(build_info, lib_name, libraries)
if lib_name == library_name:
self.build_a_library(build_info, lib_name, libraries)
return

def build_a_library(self, build_info, lib_name, libraries):
# default compilers
Expand All @@ -140,21 +175,25 @@ def build_a_library(self, build_info, lib_name, libraries):
sources = build_info.get('sources')
if sources is None or not is_sequence(sources):
raise DistutilsSetupError(("in 'libraries' option (library '%s'), " +
"'sources' must be present and must be " +
"a list of source filenames") % lib_name)
"'sources' must be present and must be " +
"a list of source filenames") % lib_name)
sources = list(sources)

c_sources, cxx_sources, f_sources, fmodule_sources \
= filter_sources(sources)
= filter_sources(sources)
requiref90 = not not fmodule_sources or \
build_info.get('language', 'c')=='f90'
build_info.get('language', 'c') == 'f90'

# save source type information so that build_ext can use it.
source_languages = []
if c_sources: source_languages.append('c')
if cxx_sources: source_languages.append('c++')
if requiref90: source_languages.append('f90')
elif f_sources: source_languages.append('f77')
if c_sources:
source_languages.append('c')
if cxx_sources:
source_languages.append('c++')
if requiref90:
source_languages.append('f90')
elif f_sources:
source_languages.append('f77')
build_info['source_languages'] = source_languages

lib_file = compiler.library_filename(lib_name,
Expand All @@ -168,8 +207,8 @@ def build_a_library(self, build_info, lib_name, libraries):

config_fc = build_info.get('config_fc', {})
if fcompiler is not None and config_fc:
log.info('using additional config_fc from setup script '\
'for fortran compiler: %s' \
log.info('using additional config_fc from setup script '
'for fortran compiler: %s'
% (config_fc,))
from numpy.distutils.fcompiler import new_fcompiler
fcompiler = new_fcompiler(compiler=fcompiler.compiler_type,
Expand All @@ -186,12 +225,14 @@ def build_a_library(self, build_info, lib_name, libraries):

# check availability of Fortran compilers
if (f_sources or fmodule_sources) and fcompiler is None:
raise DistutilsError("library %s has Fortran sources"\
" but no Fortran compiler found" % (lib_name))
raise DistutilsError("library %s has Fortran sources"
" but no Fortran compiler found" % (lib_name))

if fcompiler is not None:
fcompiler.extra_f77_compile_args = build_info.get('extra_f77_compile_args') or []
fcompiler.extra_f90_compile_args = build_info.get('extra_f90_compile_args') or []
fcompiler.extra_f77_compile_args = build_info.get(
'extra_f77_compile_args') or []
fcompiler.extra_f90_compile_args = build_info.get(
'extra_f90_compile_args') or []

macros = build_info.get('macros')
include_dirs = build_info.get('include_dirs')
Expand All @@ -203,9 +244,10 @@ def build_a_library(self, build_info, lib_name, libraries):
# where compiled F90 module files are:
module_dirs = build_info.get('module_dirs') or []
module_build_dir = os.path.dirname(lib_file)
if requiref90: self.mkpath(module_build_dir)
if requiref90:
self.mkpath(module_build_dir)

if compiler.compiler_type=='msvc':
if compiler.compiler_type == 'msvc':
# this hack works around the msvc compiler attributes
# problem, msvc uses its own convention :(
c_sources += cxx_sources
Expand Down Expand Up @@ -239,7 +281,7 @@ def build_a_library(self, build_info, lib_name, libraries):
if requiref90:
if fcompiler.module_dir_switch is None:
existing_modules = glob('*.mod')
extra_postargs += fcompiler.module_options(\
extra_postargs += fcompiler.module_options(
module_dirs, module_build_dir)

if fmodule_sources:
Expand All @@ -257,14 +299,14 @@ def build_a_library(self, build_info, lib_name, libraries):
if f in existing_modules:
continue
t = os.path.join(module_build_dir, f)
if os.path.abspath(f)==os.path.abspath(t):
if os.path.abspath(f) == os.path.abspath(t):
continue
if os.path.isfile(t):
os.remove(t)
try:
self.move_file(f, module_build_dir)
except DistutilsFileError:
log.warn('failed to move %r to %r' \
log.warn('failed to move %r to %r'
% (f, module_build_dir))

if f_sources:
Expand All @@ -278,11 +320,49 @@ def build_a_library(self, build_info, lib_name, libraries):
else:
f_objects = []

objects.extend(f_objects)

# assume that default linker is suitable for
# linking Fortran object files
compiler.create_static_lib(objects, lib_name,
libs = []

if objects:
# Go ahead and compile the c code
compiler.create_static_lib(objects, lib_name + '_msvc',
output_dir=self.build_clib,
debug=self.debug)
libs += [os.path.join(self.build_clib, lib_name + '_msvc.lib')]

if f_objects:
if lib_name == 'odepack':
f_objects = [
obj for obj in f_objects if 'xsetf' not in obj and 'xsetun' not in obj]

# link the fortran sources with gfortran
fcompiler.link_shared_object(f_objects, lib_name + '_gfortran.dll',
output_dir=self.build_clib,
library_dirs=[
self.build_clib,
'.',
],
extra_postargs=self.dlls + [
'-Wl,--out-implib,' + lib_name + '.dll.a',
'-Wl,--output-def,' + lib_name + '_gfortran.def',
'-Wl,--export-all-symbols',
'-Wl,--enable-auto-import',
],
debug=self.debug)

# Create the gfortran lib
specifier = '/MACHINE:X64'
lib_args = ['/def:{}_gfortran.def'.format(lib_name),
'/OUT:{}_gfortran.lib'.format(lib_name), specifier]
if not compiler.initialized:
compiler.initialize()
compiler.spawn([compiler.lib] + lib_args)

libs += [lib_name + '_gfortran.lib']
self.dlls.append(os.path.join(
self.build_clib, lib_name + '_gfortran.dll'))

# Combine the lib files
compiler.create_static_lib(libs, lib_name,
output_dir=self.build_clib,
debug=self.debug)

Expand Down
Loading
0