test_system_info.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. from __future__ import division, print_function
  2. import os
  3. import shutil
  4. import pytest
  5. from tempfile import mkstemp, mkdtemp
  6. from subprocess import Popen, PIPE
  7. from distutils.errors import DistutilsError
  8. from numpy.distutils import ccompiler, customized_ccompiler
  9. from numpy.testing import assert_, assert_equal
  10. from numpy.distutils.system_info import system_info, ConfigParser
  11. from numpy.distutils.system_info import default_lib_dirs, default_include_dirs
  12. from numpy.distutils import _shell_utils
  13. def get_class(name, notfound_action=1):
  14. """
  15. notfound_action:
  16. 0 - do nothing
  17. 1 - display warning message
  18. 2 - raise error
  19. """
  20. cl = {'temp1': Temp1Info,
  21. 'temp2': Temp2Info
  22. }.get(name.lower(), _system_info)
  23. return cl()
  24. simple_site = """
  25. [ALL]
  26. library_dirs = {dir1:s}{pathsep:s}{dir2:s}
  27. libraries = {lib1:s},{lib2:s}
  28. extra_compile_args = -I/fake/directory -I"/path with/spaces" -Os
  29. runtime_library_dirs = {dir1:s}
  30. [temp1]
  31. library_dirs = {dir1:s}
  32. libraries = {lib1:s}
  33. runtime_library_dirs = {dir1:s}
  34. [temp2]
  35. library_dirs = {dir2:s}
  36. libraries = {lib2:s}
  37. extra_link_args = -Wl,-rpath={lib2_escaped:s}
  38. rpath = {dir2:s}
  39. """
  40. site_cfg = simple_site
  41. fakelib_c_text = """
  42. /* This file is generated from numpy/distutils/testing/test_system_info.py */
  43. #include<stdio.h>
  44. void foo(void) {
  45. printf("Hello foo");
  46. }
  47. void bar(void) {
  48. printf("Hello bar");
  49. }
  50. """
  51. def have_compiler():
  52. """ Return True if there appears to be an executable compiler
  53. """
  54. compiler = customized_ccompiler()
  55. try:
  56. cmd = compiler.compiler # Unix compilers
  57. except AttributeError:
  58. try:
  59. if not compiler.initialized:
  60. compiler.initialize() # MSVC is different
  61. except (DistutilsError, ValueError):
  62. return False
  63. cmd = [compiler.cc]
  64. try:
  65. p = Popen(cmd, stdout=PIPE, stderr=PIPE)
  66. p.stdout.close()
  67. p.stderr.close()
  68. p.wait()
  69. except OSError:
  70. return False
  71. return True
  72. HAVE_COMPILER = have_compiler()
  73. class _system_info(system_info):
  74. def __init__(self,
  75. default_lib_dirs=default_lib_dirs,
  76. default_include_dirs=default_include_dirs,
  77. verbosity=1,
  78. ):
  79. self.__class__.info = {}
  80. self.local_prefixes = []
  81. defaults = {'library_dirs': '',
  82. 'include_dirs': '',
  83. 'runtime_library_dirs': '',
  84. 'rpath': '',
  85. 'src_dirs': '',
  86. 'search_static_first': "0",
  87. 'extra_compile_args': '',
  88. 'extra_link_args': ''}
  89. self.cp = ConfigParser(defaults)
  90. # We have to parse the config files afterwards
  91. # to have a consistent temporary filepath
  92. def _check_libs(self, lib_dirs, libs, opt_libs, exts):
  93. """Override _check_libs to return with all dirs """
  94. info = {'libraries': libs, 'library_dirs': lib_dirs}
  95. return info
  96. class Temp1Info(_system_info):
  97. """For testing purposes"""
  98. section = 'temp1'
  99. class Temp2Info(_system_info):
  100. """For testing purposes"""
  101. section = 'temp2'
  102. class TestSystemInfoReading(object):
  103. def setup(self):
  104. """ Create the libraries """
  105. # Create 2 sources and 2 libraries
  106. self._dir1 = mkdtemp()
  107. self._src1 = os.path.join(self._dir1, 'foo.c')
  108. self._lib1 = os.path.join(self._dir1, 'libfoo.so')
  109. self._dir2 = mkdtemp()
  110. self._src2 = os.path.join(self._dir2, 'bar.c')
  111. self._lib2 = os.path.join(self._dir2, 'libbar.so')
  112. # Update local site.cfg
  113. global simple_site, site_cfg
  114. site_cfg = simple_site.format(**{
  115. 'dir1': self._dir1,
  116. 'lib1': self._lib1,
  117. 'dir2': self._dir2,
  118. 'lib2': self._lib2,
  119. 'pathsep': os.pathsep,
  120. 'lib2_escaped': _shell_utils.NativeParser.join([self._lib2])
  121. })
  122. # Write site.cfg
  123. fd, self._sitecfg = mkstemp()
  124. os.close(fd)
  125. with open(self._sitecfg, 'w') as fd:
  126. fd.write(site_cfg)
  127. # Write the sources
  128. with open(self._src1, 'w') as fd:
  129. fd.write(fakelib_c_text)
  130. with open(self._src2, 'w') as fd:
  131. fd.write(fakelib_c_text)
  132. # We create all class-instances
  133. def site_and_parse(c, site_cfg):
  134. c.files = [site_cfg]
  135. c.parse_config_files()
  136. return c
  137. self.c_default = site_and_parse(get_class('default'), self._sitecfg)
  138. self.c_temp1 = site_and_parse(get_class('temp1'), self._sitecfg)
  139. self.c_temp2 = site_and_parse(get_class('temp2'), self._sitecfg)
  140. def teardown(self):
  141. # Do each removal separately
  142. try:
  143. shutil.rmtree(self._dir1)
  144. except Exception:
  145. pass
  146. try:
  147. shutil.rmtree(self._dir2)
  148. except Exception:
  149. pass
  150. try:
  151. os.remove(self._sitecfg)
  152. except Exception:
  153. pass
  154. def test_all(self):
  155. # Read in all information in the ALL block
  156. tsi = self.c_default
  157. assert_equal(tsi.get_lib_dirs(), [self._dir1, self._dir2])
  158. assert_equal(tsi.get_libraries(), [self._lib1, self._lib2])
  159. assert_equal(tsi.get_runtime_lib_dirs(), [self._dir1])
  160. extra = tsi.calc_extra_info()
  161. assert_equal(extra['extra_compile_args'], ['-I/fake/directory', '-I/path with/spaces', '-Os'])
  162. def test_temp1(self):
  163. # Read in all information in the temp1 block
  164. tsi = self.c_temp1
  165. assert_equal(tsi.get_lib_dirs(), [self._dir1])
  166. assert_equal(tsi.get_libraries(), [self._lib1])
  167. assert_equal(tsi.get_runtime_lib_dirs(), [self._dir1])
  168. def test_temp2(self):
  169. # Read in all information in the temp2 block
  170. tsi = self.c_temp2
  171. assert_equal(tsi.get_lib_dirs(), [self._dir2])
  172. assert_equal(tsi.get_libraries(), [self._lib2])
  173. # Now from rpath and not runtime_library_dirs
  174. assert_equal(tsi.get_runtime_lib_dirs(key='rpath'), [self._dir2])
  175. extra = tsi.calc_extra_info()
  176. assert_equal(extra['extra_link_args'], ['-Wl,-rpath=' + self._lib2])
  177. @pytest.mark.skipif(not HAVE_COMPILER, reason="Missing compiler")
  178. def test_compile1(self):
  179. # Compile source and link the first source
  180. c = customized_ccompiler()
  181. previousDir = os.getcwd()
  182. try:
  183. # Change directory to not screw up directories
  184. os.chdir(self._dir1)
  185. c.compile([os.path.basename(self._src1)], output_dir=self._dir1)
  186. # Ensure that the object exists
  187. assert_(os.path.isfile(self._src1.replace('.c', '.o')) or
  188. os.path.isfile(self._src1.replace('.c', '.obj')))
  189. finally:
  190. os.chdir(previousDir)
  191. @pytest.mark.skipif(not HAVE_COMPILER, reason="Missing compiler")
  192. @pytest.mark.skipif('msvc' in repr(ccompiler.new_compiler()),
  193. reason="Fails with MSVC compiler ")
  194. def test_compile2(self):
  195. # Compile source and link the second source
  196. tsi = self.c_temp2
  197. c = customized_ccompiler()
  198. extra_link_args = tsi.calc_extra_info()['extra_link_args']
  199. previousDir = os.getcwd()
  200. try:
  201. # Change directory to not screw up directories
  202. os.chdir(self._dir2)
  203. c.compile([os.path.basename(self._src2)], output_dir=self._dir2,
  204. extra_postargs=extra_link_args)
  205. # Ensure that the object exists
  206. assert_(os.path.isfile(self._src2.replace('.c', '.o')))
  207. finally:
  208. os.chdir(previousDir)