Test for existence of a function within a tuple of libraries. This is used as a smoke test to check whether a certain library is available. As a test, this creates a simple C program that calls the specified function, and then distutils is used to compile that progr
(self, funcname, libraries, library_dirs=None, verbose=False)
| 314 | return [] |
| 315 | |
| 316 | def has_function(self, funcname, libraries, library_dirs=None, verbose=False): |
| 317 | ''' |
| 318 | Test for existence of a function within a tuple of libraries. |
| 319 | |
| 320 | This is used as a smoke test to check whether a certain library is available. |
| 321 | As a test, this creates a simple C program that calls the specified function, |
| 322 | and then distutils is used to compile that program and link it with the specified libraries. |
| 323 | Returns True if both the compile and link are successful, False otherwise. |
| 324 | ''' |
| 325 | tempdir = None # we create a temporary directory to hold various files |
| 326 | filestderr = None # handle to open file to which we redirect stderr |
| 327 | oldstderr = None # file descriptor for stderr |
| 328 | try: |
| 329 | # Echo compile and link commands that are used. |
| 330 | if verbose: |
| 331 | distutils.log.set_verbosity(1) |
| 332 | |
| 333 | # Create a compiler object. |
| 334 | compiler = distutils.ccompiler.new_compiler(verbose=verbose) |
| 335 | |
| 336 | # Configure compiler and linker to build according to Python install. |
| 337 | distutils.sysconfig.customize_compiler(compiler) |
| 338 | |
| 339 | # Create a temporary directory to hold test files. |
| 340 | tempdir = tempfile.mkdtemp() |
| 341 | |
| 342 | # Define a simple C program that calls the function in question |
| 343 | prog = "void %s(void); int main(int argc, char** argv) { %s(); return 0; }" % (funcname, funcname) |
| 344 | |
| 345 | # Write the test program to a file. |
| 346 | filename = os.path.join(tempdir, 'test.c') |
| 347 | with open(filename, 'w') as f: |
| 348 | f.write(prog) |
| 349 | |
| 350 | # Redirect stderr file descriptor to a file to silence compile/link warnings. |
| 351 | if not verbose: |
| 352 | filestderr = open(os.path.join(tempdir, 'stderr.txt'), 'w') |
| 353 | oldstderr = os.dup(sys.stderr.fileno()) |
| 354 | os.dup2(filestderr.fileno(), sys.stderr.fileno()) |
| 355 | |
| 356 | # Workaround for behavior in distutils.ccompiler.CCompiler.object_filenames() |
| 357 | # Otherwise, a local directory will be used instead of tempdir |
| 358 | drive, driveless_filename = os.path.splitdrive(filename) |
| 359 | root_dir = driveless_filename[0] if os.path.isabs(driveless_filename) else '' |
| 360 | output_dir = os.path.join(drive, root_dir) |
| 361 | |
| 362 | # Attempt to compile the C program into an object file. |
| 363 | cflags = shlex.split(os.environ.get('CFLAGS', "")) |
| 364 | objs = compiler.compile([filename], output_dir=output_dir, extra_preargs=self.strip_empty_entries(cflags)) |
| 365 | |
| 366 | # Attempt to link the object file into an executable. |
| 367 | # Be sure to tack on any libraries that have been specified. |
| 368 | ldflags = shlex.split(os.environ.get('LDFLAGS', "")) |
| 369 | compiler.link_executable(objs, |
| 370 | os.path.join(tempdir, 'a.out'), |
| 371 | extra_preargs=self.strip_empty_entries(ldflags), |
| 372 | libraries=libraries, |
| 373 | library_dirs=library_dirs) |
no test coverage detected