I cloned the git master
branch of matplotlib
and I got to build it in Mac OSX. When I try to do the same in x86_64 GNU/Linux I get this output and error:
BUILDING MATPLOTLIB
matplotlib: yes [1.3.x]
python: yes [3.3.1 (default, May 7 2013, 17:57:31) [GCC
4.8.0]]
platform: yes [linux]
REQUIRED DEPENDENCIES AND EXTENSIONS
numpy: yes [version 1.7.1]
dateutil: yes [using dateutil version 2.1]
tornado: yes [using tornado version 3.0.1]
pyparsing: yes [using pyparsing version 2.0.0]
pycxx: yes [Official versions of PyCXX are not compatible
with Python 3.x. Using local copy]
libagg: yes [pkg-config information for 'libagg' could not
be found. Using local copy.]
freetype: yes [version 9.22.3]
Traceback (most recent call last):
File "./setup.py", line 133, in <module>
result = package.check()
File "/home/khyox/matplotlib/setupext.py", line 808, in check
min_version='1.2')
File "/home/khyox/matplotlib/setupext.py", line 429, in _check_for_pkg_config
ext = self.get_extension()
File "/home/khyox/matplotlib/setupext.py", line 821, in get_extension
CXX().add_flags(ext)
File "/home/khyox/matplotlib/setupext.py", line 716, in add_flags
ext.sources.extend(glob.glob('CXX/*.cxx'))
AttributeError: 'map' object has no attribute 'extend'
I traced the error to the PNG (libpng
) package parsing. I tried with several versions of this library (1.2.49, 1.5.16 and 1.6.2), all supported by matplotlib
(should be version 1.2 or higher for libpng
), but this not solved the issue. Looking for helping differences, in Mac OSX I compiled Python3.3 with Clang 4.1 (said to be GCC 4.2 compatible) and in this x86_64 GNU/Linux machine, I used GCC 4.8.0, but I hardly believe that the problem could be related with this...
Any clue? Thank you very much in advance!
Solution: As suggested by @DSM in the comments below, a workaround is to edit setupext.py and, in the function make_extension(name, files, *args, **kwargs)
just add this line:
ext.sources = list(ext.sources)
after the line:
ext = Extension(name, files, *args, **kwargs)
On the other hand, @tcaswell pointed out the suspect of the issue: distutils
. In short, in order to install all the dependencies for matplotlib
I used distribute3
and its last release overrides the class distutils.core.Extension
converting its sources
member to a map
instead of a list
(it is expected to be a list of strings, as documented in docs.python.org).
Entering in more details, if we add some debugging stuff, the output becomes:
BUILDING MATPLOTLIB
matplotlib: yes [1.3.x]
python: yes [3.3.1 (default, May 7 2013, 17:57:31) [GCC
4.8.0]]
platform: yes [linux]
REQUIRED DEPENDENCIES AND EXTENSIONS
Call distutils.core.Extension constructor with name=test and files=[]
Printing (ext = distutils.core.Extension).sources : <map object at 0x7f920c869e50>
The map object is empty!
numpy: yes [version 1.7.1]
dateutil: yes [using dateutil version 2.1]
tornado: yes [using tornado version 3.0.1]
pyparsing: yes [using pyparsing version 2.0.0]
pycxx: yes [Official versions of PyCXX are not compatible
with Python 3.x. Using local copy]
libagg: yes [pkg-config information for 'libagg' could not
be found. Using local copy.]
Call distutils.core.Extension constructor with name=test and files=[]
Printing (ext = distutils.core.Extension).sources : <map object at 0x7f9208e81490>
The map object is empty!
freetype: yes [version 9.22.3]
Call distutils.core.Extension constructor with name=matplotlib._png and files=['src/_png.cpp', 'src/mplutils.cpp']
Printing (ext = distutils.core.Extension).sources : <map object at 0x7f9208e81510>
The map object is empty!
Traceback (most recent call last):
File "setup.py", line 133, in <module>
result = package.check()
File "/home/khyox/matplotlib/setupext.py", line 817, in check
min_version='1.2')
File "/home/khyox/matplotlib/setupext.py", line 438, in _check_for_pkg_config
ext = self.get_extension()
File "/home/khyox/matplotlib/setupext.py", line 830, in get_extension
CXX().add_flags(ext)
File "/home/khyox/matplotlib/setupext.py", line 725, in add_flags
ext.sources.extend(glob.glob('CXX/*.cxx'))
AttributeError: 'map' object has no attribute 'extend'
So, instead of being a list
, the sources
member of ext
appears as a map
. What is more, it fails to contain the source files when passed to the constructor, as seen for the matplotlib._png
case, that is, when processing the libpng
extension.
I followed the source of such strange behavior to the file extension.py of the setuptools
provided by distribute3
(see last line):
class Extension(_Extension):
"""Extension that uses '.c' files in place of '.pyx' files"""
def __init__(self, *args, **kw):
_Extension.__init__(self, *args, **kw)
if not have_pyrex():
self._convert_pyx_sources_to_c()
def _convert_pyx_sources_to_c(self):
"convert .pyx extensions to .c"
def pyx_to_c(source):
if source.endswith('.pyx'):
source = source[:-4] + '.c'
return source
self.sources = map(pyx_to_c, self.sources)
Nevertheless, in the last distribute
commit (newer than the last one of distribute3
), it seems to be solved:
class Extension(_Extension):
"""Extension that uses '.c' files in place of '.pyx' files"""
if not have_pyrex:
# convert .pyx extensions to .c
def __init__(self,*args,**kw):
_Extension.__init__(self,*args,**kw)
sources = []
for s in self.sources:
if s.endswith('.pyx'):
sources.append(s[:-3]+'c')
else:
sources.append(s)
self.sources = sources
So, once distribute3
will be synchronized with distribute
this problem will probably disappear. Until then, the hack suggested by @DSM is working.