diff --git a/src/Makefile.in b/src/Makefile.in index eba5e9a4c75..81a28b3758e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -18,7 +18,6 @@ all: sage ## In this way we make sure that all of the sagelib build's source paths are communicated through ## the current directory (for the source tree). ## Building takes places in the build/ subdirectory. -## The environment variable SAGE_CYTHONIZED needs to point to build/cythonized. ## ## As a special exception, we feed SAGE_PKGS. This is needed by src/sage_setup/optional_extension.py ## via src/sage/misc/package.py. Hoping that #20382 will make this unnecessary. @@ -38,7 +37,6 @@ sage: SAGE_DOC_SRC=/doesnotexist \ SAGE_BUILD_DIR=/doesnotexist \ SAGE_PKGS=$(abs_top_srcdir)/build/pkgs \ - SAGE_CYTHONIZED=$(abs_builddir)/build/cythonized \ && sage-python23 -u setup.py --no-user-cfg build install if [ "$$UNAME" = "CYGWIN" ]; then \ sage-rebase.sh "$$SAGE_LOCAL" 2>/dev/null; \ diff --git a/src/sage/env.py b/src/sage/env.py index c50beb14bf9..3f670639e32 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -107,8 +107,6 @@ def _add_variable_or_fallback(key, fallback, force=False): _add_variable_or_fallback('SAGE_LIB', SITE_PACKAGES[0]) -_add_variable_or_fallback('SAGE_CYTHONIZED', opj('$SAGE_ROOT', 'src', 'build', 'cythonized')) - # Used by sage/misc/package.py. Should be SAGE_SRC_ROOT in VPATH. _add_variable_or_fallback('SAGE_PKGS', opj('$SAGE_ROOT', 'build', 'pkgs')) diff --git a/src/sage_setup/clean.py b/src/sage_setup/clean.py index 25bbf79a1f6..b7c222b26aa 100644 --- a/src/sage_setup/clean.py +++ b/src/sage_setup/clean.py @@ -71,12 +71,13 @@ def _find_stale_files(site_packages, python_packages, python_modules, ext_module course. We check that when the doctest is being run, that is, after installation, there are no stale files:: - sage: from sage.env import SAGE_SRC, SAGE_LIB, SAGE_CYTHONIZED + sage: from sage.env import SAGE_SRC, SAGE_LIB + sage: cythonized_dir = os.path.join(SAGE_SRC, "build", "cythonized") sage: from sage_setup.find import find_python_sources, find_extra_files sage: python_packages, python_modules = find_python_sources( ....: SAGE_SRC, ['sage', 'sage_setup']) sage: extra_files = find_extra_files(python_packages, SAGE_SRC, - ....: SAGE_CYTHONIZED, ["ntlwrap.cpp"]) + ....: cythonized_dir, ["ntlwrap.cpp"]) sage: from sage_setup.clean import _find_stale_files TODO: move ``module_list.py`` into ``sage_setup`` and also check diff --git a/src/sage_setup/find.py b/src/sage_setup/find.py index cba29bfd944..d4d366bd92e 100644 --- a/src/sage_setup/find.py +++ b/src/sage_setup/find.py @@ -101,8 +101,9 @@ def find_extra_files(packages, src_dir, cythonized_dir, special_filenames=[]): EXAMPLES:: sage: from sage_setup.find import find_extra_files - sage: from sage.env import SAGE_SRC, SAGE_CYTHONIZED - sage: find_extra_files(["sage.ext.interpreters"], SAGE_SRC, SAGE_CYTHONIZED) + sage: from sage.env import SAGE_SRC + sage: cythonized_dir = os.path.join(SAGE_SRC, "build", "cythonized") + sage: find_extra_files(["sage.ext.interpreters"], SAGE_SRC, cythonized_dir) [('sage/ext/interpreters', ['.../src/sage/ext/interpreters/wrapper_cdf.pxd', ...wrapper_cdf.h...])] """ diff --git a/src/setup.py b/src/setup.py index 6354427b851..74ba47ae962 100755 --- a/src/setup.py +++ b/src/setup.py @@ -13,6 +13,9 @@ from distutils.errors import (DistutilsSetupError, DistutilsModuleError, DistutilsOptionError) +# This import allows instancemethods to be pickable +import fpickle_setup + def excepthook(*exc): """ @@ -46,18 +49,13 @@ def excepthook(*exc): sys.excepthook = excepthook -######################################################### -### Check build-base -######################################################### - -build_base = 'build' # the distutils default. Changing it is not supported by this setup.sh. - ######################################################### ### Set source directory ######################################################### import sage.env sage.env.SAGE_SRC = os.getcwd() +from sage.env import * ######################################################### ### List of Extensions @@ -67,7 +65,6 @@ def excepthook(*exc): ######################################################### from module_list import ext_modules, library_order, aliases -from sage.env import * from sage_setup.find import find_extra_files ######################################################### @@ -88,7 +85,6 @@ def excepthook(*exc): # search for dependencies and add to gcc -I include_dirs = sage_include_directories(use_sources=True) -include_dirs.append(SAGE_CYTHONIZED) # Look for libraries in $SAGE_LOCAL/lib library_dirs = [os.path.join(SAGE_LOCAL, "lib")] @@ -196,67 +192,6 @@ def __call__(self, *args): } -def sage_create_extension(template, kwds): - """ - Create a distutils Extension given data from Cython - - This adjust the ``kwds`` in the following ways: - - - Make everything depend on *this* setup.py file - - - Add dependencies on header files for certain libraries - - - Ensure that C++ extensions link with -lstdc++ - - - Sort the libraries according to the library order - - - Add some default compile/link args and directories - - - Drop -std=c99 and similar from C++ extensions - - - Ensure that each flag, library, ... is listed at most once - """ - lang = kwds.get('language', 'c') - - # Libraries: add stdc++ if needed and sort them - libs = kwds.get('libraries', []) - if lang == 'c++': - libs = libs + ['stdc++'] - kwds['libraries'] = sorted(set(libs), - key=lambda lib: library_order.get(lib, 0)) - - # Dependencies: add setup.py and lib_headers - depends = kwds.get('depends', []) + [__file__] - for lib, headers in lib_headers.items(): - if lib in libs: - depends += headers - kwds['depends'] = depends # These are sorted and uniq'ed by Cython - - # Process extra_compile_args - cflags = [] - for flag in kwds.get('extra_compile_args', []): - if lang == "c++": - if flag.startswith("-std=") and "++" not in flag: - continue # Skip -std=c99 and similar for C++ - cflags.append(flag) - cflags = extra_compile_args + cflags - kwds['extra_compile_args'] = stable_uniq(cflags) - - # Process extra_link_args - ldflags = kwds.get('extra_link_args', []) + extra_link_args - kwds['extra_link_args'] = stable_uniq(ldflags) - - # Process library_dirs - lib_dirs = kwds.get('library_dirs', []) + library_dirs - kwds['library_dirs'] = stable_uniq(lib_dirs) - - # Process include_dirs - inc_dirs = kwds.get('include_dirs', []) + include_dirs - kwds['include_dirs'] = stable_uniq(inc_dirs) - - return default_create_extension(template, kwds) - - class sage_build_cython(Command): name = 'build_cython' description = "compile Cython extensions into C/C++ extensions" @@ -278,6 +213,7 @@ class sage_build_cython(Command): def initialize_options(self): self.extensions = None + self.build_base = None self.build_dir = None # Always have Cython produce debugging info by default, unless @@ -295,9 +231,10 @@ def initialize_options(self): def finalize_options(self): self.extensions = self.distribution.ext_modules - # TODO: Could get source path for Cythonized files from the build - # command, rather than relying solely on SAGE_CYTHONIZED - self.build_dir = SAGE_CYTHONIZED + # Let Cython generate its files in the "cythonized" + # subdirectory of the build_base directory. + self.set_undefined_options('build', ('build_base', 'build_base')) + self.build_dir = os.path.join(self.build_base, "cythonized") # Inherit some options from the 'build_ext' command if possible # (this in turn implies inheritance from the 'build' command) @@ -398,7 +335,7 @@ def get_cythonized_package_files(self): dist = self.distribution self.cythonized_files = find_extra_files(dist.packages, - ".", SAGE_CYTHONIZED, ["ntlwrap.cpp"]) + ".", self.build_dir, ["ntlwrap.cpp"]) return self.cythonized_files @@ -424,7 +361,7 @@ def run(self): aliases=aliases, compiler_directives=self.cython_directives, compile_time_env={'PY_VERSION_HEX':sys.hexversion}, - create_extension=sage_create_extension, + create_extension=self.create_extension, # Debugging gdb_debug=self.debug, output_dir=self.build_dir, @@ -438,7 +375,7 @@ def run(self): with open(self._version_file, 'w') as f: f.write(self._version_stamp) - # Finally, copy relevant cythonized files from the SAGE_CYTHONIZED + # Finally, copy relevant cythonized files from build/cythonized # tree into the build-lib tree for (dst_dir, src_files) in self.get_cythonized_package_files(): dst = os.path.join(self.build_lib, dst_dir) @@ -446,6 +383,66 @@ def run(self): for src in src_files: self.copy_file(src, dst, preserve_mode=False) + def create_extension(self, template, kwds): + """ + Create a distutils Extension given data from Cython. + + This adjust the ``kwds`` in the following ways: + + - Make everything depend on *this* setup.py file + + - Add dependencies on header files for certain libraries + + - Ensure that C++ extensions link with -lstdc++ + + - Sort the libraries according to the library order + + - Add some default compile/link args and directories + + - Drop -std=c99 and similar from C++ extensions + + - Ensure that each flag, library, ... is listed at most once + """ + lang = kwds.get('language', 'c') + + # Libraries: add stdc++ if needed and sort them + libs = kwds.get('libraries', []) + if lang == 'c++': + libs = libs + ['stdc++'] + kwds['libraries'] = sorted(set(libs), + key=lambda lib: library_order.get(lib, 0)) + + # Dependencies: add setup.py and lib_headers + depends = kwds.get('depends', []) + [__file__] + for lib, headers in lib_headers.items(): + if lib in libs: + depends += headers + kwds['depends'] = depends # These are sorted and uniq'ed by Cython + + # Process extra_compile_args + cflags = [] + for flag in kwds.get('extra_compile_args', []): + if lang == "c++": + if flag.startswith("-std=") and "++" not in flag: + continue # Skip -std=c99 and similar for C++ + cflags.append(flag) + cflags = extra_compile_args + cflags + kwds['extra_compile_args'] = stable_uniq(cflags) + + # Process extra_link_args + ldflags = kwds.get('extra_link_args', []) + extra_link_args + kwds['extra_link_args'] = stable_uniq(ldflags) + + # Process library_dirs + lib_dirs = kwds.get('library_dirs', []) + library_dirs + kwds['library_dirs'] = stable_uniq(lib_dirs) + + # Process include_dirs + inc_dirs = kwds.get('include_dirs', []) + include_dirs + [self.build_dir] + kwds['include_dirs'] = stable_uniq(inc_dirs) + + return default_create_extension(template, kwds) + ######################################################################## ## @@ -517,7 +514,6 @@ def execute_list_of_commands_in_parallel(command_list, nthreads): command_list[i] = command_list[i] + (progress,) from multiprocessing import Pool - import fpickle_setup #doing this import will allow instancemethods to be pickable # map_async handles KeyboardInterrupt correctly if an argument is # given to get(). Plain map() and apply_async() do not work # correctly, see Trac #16113.