"Fossies" - the Fresh Open Source Software Archive

Member "relax-5.0.0/sconstruct" (2 Dec 2019, 29777 Bytes) of package /linux/privat/relax-5.0.0.src.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "sconstruct": 4.1.3_vs_5.0.0.

    1 #! /usr/bin/python
    2 # That line was just so programs like gvim or emacs will understand that this is Python code!  Don't
    3 # make this file executable.
    4 
    5 ###############################################################################
    6 #                                                                             #
    7 # Copyright (C) 2006-2008,2010-2012,2014-2016,2018-2019 Edward d'Auvergne     #
    8 # Copyright (C) 2009 Sebastien Morin                                          #
    9 # Copyright (C) 2014 Troels E. Linnet                                         #
   10 #                                                                             #
   11 # This file is part of the program relax (http://www.nmr-relax.com).          #
   12 #                                                                             #
   13 # This program is free software: you can redistribute it and/or modify        #
   14 # it under the terms of the GNU General Public License as published by        #
   15 # the Free Software Foundation, either version 3 of the License, or           #
   16 # (at your option) any later version.                                         #
   17 #                                                                             #
   18 # This program is distributed in the hope that it will be useful,             #
   19 # but WITHOUT ANY WARRANTY; without even the implied warranty of              #
   20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
   21 # GNU General Public License for more details.                                #
   22 #                                                                             #
   23 # You should have received a copy of the GNU General Public License           #
   24 # along with relax; if not, write to the Free Software                        #
   25 #                                                                             #
   26 ###############################################################################
   27 
   28 
   29 # Import statements.
   30 from os import F_OK, access, getcwd, path, remove, rmdir, sep, walk, environ
   31 import platform
   32 from re import search
   33 from shutil import rmtree
   34 from subprocess import PIPE, Popen
   35 import sys
   36 from tempfile import mkdtemp
   37 
   38 # Scons modules.
   39 from scons.distrib import package, gpg_sign
   40 from scons.install import install, uninstall
   41 from scons.manuals import clean_manual_files, compile_api_manual_html, compile_user_manual_html, compile_user_manual_pdf, copyright_file, fetch_docstrings, replicate_title_check, version_file
   42 from SCons.Script import ARGUMENTS
   43 import SCons.Util
   44 
   45 # relax version file.
   46 from version import version
   47 
   48 
   49 
   50 ########################
   51 # Paths and file names #
   52 ########################
   53 
   54 # The operating system.
   55 SYSTEM = platform.uname()[0]
   56 
   57 # The machine type.
   58 MACH = platform.uname()[4]
   59 
   60 # Symbolic link flag.
   61 SYMLINK_FLAG = 1
   62 
   63 # Determine the target architecture based on the Python binary (currently Windows only).
   64 TARGET_ARCH = None
   65 arch = platform.architecture()[0]
   66 if arch == '32bit':
   67     TARGET_ARCH = 'x86'
   68 elif arch == '64bit':
   69     TARGET_ARCH = 'x86_64'
   70 
   71 # GNU/Linux.
   72 if SYSTEM == 'Linux':
   73     # System specific string.
   74     SYS = 'GNU-Linux'
   75 
   76     # Linux installation path.
   77     INSTALL_PATH = '/usr/local'
   78 
   79 
   80 # MS Windows.
   81 elif SYSTEM == 'Windows' or SYSTEM == 'Microsoft':
   82     # Set the system to 'Windows' no matter what.
   83     SYSTEM = 'Windows'
   84 
   85     # 32 bit.
   86     if arch == '32bit':
   87         SYS = 'Win32'
   88 
   89     # 64 bit.
   90     elif arch == '64bit':
   91         SYS = 'Win64'
   92 
   93     # Unknown.
   94     else:
   95         SYS = 'Win'
   96 
   97     # Windows installation path.
   98     INSTALL_PATH = 'C:\\'
   99 
  100     # No symlinks!
  101     SYMLINK_FLAG = 0
  102 
  103 
  104 # Mac OS X.
  105 elif SYSTEM == 'Darwin':
  106     # System specific string.
  107     SYS = SYSTEM
  108 
  109     # Mac OS X installation path.
  110     INSTALL_PATH = sys.prefix + sep + 'local'
  111 
  112 
  113 # All other operating systems.
  114 else:
  115     # System specific string.
  116     SYS = SYSTEM
  117 
  118     # Installation path.
  119     INSTALL_PATH = sys.prefix + sep + 'local'
  120 
  121 
  122 
  123 # Installation.
  124 ###############
  125 
  126 # Relax installation directory.
  127 RELAX_PATH = INSTALL_PATH + sep + 'relax'
  128 
  129 # Installation path for binaries.
  130 BIN_PATH = INSTALL_PATH + sep + 'bin'
  131 
  132 # Symbolic link installation path.
  133 SYMLINK = BIN_PATH + sep + 'relax'
  134 
  135 
  136 
  137 # The distribution files.
  138 #########################
  139 
  140 if SYSTEM == 'Windows':
  141     BIN_FILE = 'relax-' + version + '.' + SYS
  142     SRC_FILE = 'relax-' + version + '.src'
  143     DIST_TYPE = 'zip'
  144 elif SYSTEM == 'Darwin':
  145     BIN_FILE = 'relax-' + version + '.' + SYS
  146     SRC_FILE = 'relax-' + version + '.src'
  147     DIST_TYPE = 'dmg'
  148 
  149 else:
  150     BIN_FILE = 'relax-' + version + '.' + SYS + '.' + MACH
  151     SRC_FILE = 'relax-' + version + '.src'
  152     DIST_TYPE = 'tar'
  153 
  154 
  155 # GPG key.
  156 ##########
  157 
  158 GPG_KEY = ARGUMENTS.get('key')
  159 
  160 
  161 # Documentation.
  162 ################
  163 
  164 # Documentation directory.
  165 DOCS_DIR = 'docs' + sep
  166 
  167 # LaTeX directory.
  168 LATEX_DIR = 'docs' + sep + 'latex' + sep
  169 
  170 
  171 
  172 
  173 class Main:
  174     def __init__(self):
  175         """Initialise the main building targets.
  176 
  177         This function sets up the Scons build Environments, sets custom Builders, sets the build
  178         targets, and sets the build dependancies.
  179         """
  180 
  181         # Initialisation.
  182         #################
  183 
  184         # Set the help message.
  185         self.help()
  186 
  187 
  188         # C module compilation.
  189         #######################
  190 
  191         # Setup the rules for building the relaxation curve fitting C modules (and set it as the default).
  192         self.relax_fit()
  193         Default(self.relax_fit_object)
  194 
  195 
  196 
  197         # Program installation.
  198         #######################
  199 
  200         # Install target.
  201         install_env = Environment(BUILDERS={'install' : Builder(action=install)},
  202                                   BIN_PATH=BIN_PATH,
  203                                   INSTALL_PATH=INSTALL_PATH,
  204                                   RELAX_PATH=RELAX_PATH,
  205                                   SYMLINK=SYMLINK,
  206                                   SYMLINK_FLAG=SYMLINK_FLAG)
  207         install_env.install(target='install', source=None)
  208 
  209         # Uninstall target.
  210         uninstall_env = Environment(BUILDERS={'uninstall' : Builder(action=uninstall)},
  211                                   BIN_PATH=BIN_PATH,
  212                                   INSTALL_PATH=INSTALL_PATH,
  213                                   RELAX_PATH=RELAX_PATH,
  214                                   SYMLINK=SYMLINK,
  215                                   SYMLINK_FLAG=SYMLINK_FLAG)
  216         uninstall_env.uninstall(target='uninstall', source=None)
  217 
  218 
  219 
  220         # Distribution packages.
  221         ########################
  222 
  223         # Target for creating the binary distribution file.
  224         binary_dist_env = Environment(BUILDERS={'dummy' : Builder(action=self.dummy)})
  225         binary_dist_env.dummy(target='binary_dist', source=None)
  226         binary_dist_env.Depends('binary_dist', 'version_check')           # First check the program version number.
  227         binary_dist_env.Depends('binary_dist', self.relax_fit_object)     # Compile the C code.
  228         binary_dist_env.Depends('binary_dist', 'manual_clean_nodeps')     # Clean up the temporary manual files.
  229         binary_dist_env.Depends('binary_dist', 'clean')                   # Then clean up all other temporary files.
  230         binary_dist_env.Depends('binary_dist', 'package_bin')             # Package the binary distribution.
  231         binary_dist_env.Depends('binary_dist', 'gpg_bin')                 # GPG sign the binary distribution file.
  232 
  233         # Target for creating the source distribution file.
  234         source_dist_env = Environment(BUILDERS={'dummy' : Builder(action=self.dummy)})
  235         source_dist_env.dummy(target='source_dist', source=None)
  236         source_dist_env.Depends('source_dist', 'version_check')           # First check the program version number.
  237         source_dist_env.Depends('source_dist', 'manual_clean_nodeps')     # Clean up the temporary manual files.
  238         source_dist_env.Depends('source_dist', 'clean_all')               # Then clean up the sources.
  239         source_dist_env.Depends('source_dist', 'package_src')             # Package the source distribution.
  240         source_dist_env.Depends('source_dist', 'gpg_src')                 # GPG sign the source distribution file.
  241 
  242         # Target for packaging the binary distribution.
  243         package_bin_env = Environment(BUILDERS={'archive' : Builder(action=package)},
  244                                       DIST_FILE=BIN_FILE,
  245                                       DIST_TYPE=DIST_TYPE)
  246         package_bin_env.archive(target='package_bin', source=None)
  247         package_bin_env.Depends('package_bin', 'version_check')     # Check the program version number first.
  248 
  249         # Target for packaging the source distribution.
  250         package_src_env = Environment(BUILDERS={'archive' : Builder(action=package)},
  251                                       DIST_FILE=SRC_FILE,
  252                                       DIST_TYPE='ALL')
  253         package_src_env.archive(target='package_src', source=None)
  254         package_src_env.Depends('package_src', 'version_check')     # Check the program version number first.
  255 
  256         # Target for creating a GPG signature of the binary distribution file.
  257         gpg_bin_env = Environment(BUILDERS={'sign' : Builder(action=gpg_sign)},
  258                                   DIST_FILE=BIN_FILE,
  259                                   DIST_TYPE=DIST_TYPE,
  260                                   GPG_KEY=GPG_KEY)
  261         gpg_bin_env.sign(target='gpg_bin', source=None)
  262         gpg_bin_env.Depends('gpg_bin', 'version_check')     # Check the program version number before signing.
  263 
  264         # Target for creating a GPG signature of the source distribution file.
  265         gpg_src_env = Environment(BUILDERS={'sign' : Builder(action=gpg_sign)},
  266                                   DIST_FILE=SRC_FILE,
  267                                   DIST_TYPE='ALL',
  268                                   GPG_KEY=GPG_KEY)
  269         gpg_src_env.sign(target='gpg_src', source=None)
  270         gpg_src_env.Depends('gpg_src', 'version_check')     # Check the program version number before signing.
  271 
  272 
  273 
  274         # relax version checking.
  275         #########################
  276 
  277         # relax version number checking target.
  278         version_check_env = Environment(BUILDERS={'check' : Builder(action=self.test_version)})
  279         version_check_env.check(target='version_check', source=None)
  280 
  281 
  282 
  283         # Cleaning up.
  284         ##############
  285 
  286         # Clean target.
  287         clean_all_env = Environment(BUILDERS={'clean' : Builder(action=self.clean_all_files)})
  288         clean_all_env.clean(target='clean_all', source=None)
  289         clean_all_env.Depends('clean_all', 'clean')            # Run the 'clean' target.
  290         clean_all_env.Depends('clean_all', 'manual_clean')     # Run the 'manual_clean' target.
  291 
  292         # Target for removing temporary files.
  293         clean_env = Environment(BUILDERS={'clean' : Builder(action=self.clean_files)})
  294         clean_env.Depends('clean', 'manual_clean')
  295         clean_env.clean(target='clean', source=None)
  296 
  297 
  298 
  299         # relax manuals.
  300         ################
  301 
  302         # Create the manual build environment.
  303         manual_env = Environment(DOCS_DIR=DOCS_DIR,
  304                                  LATEX_DIR=LATEX_DIR,
  305                                  SYSTEM=SYSTEM)
  306 
  307 
  308         # Set up the builder for the standard manual targets (using the self.dummy function).
  309         manual_env.Append(BUILDERS={'Manual' : Builder(action=self.dummy)})
  310 
  311         # Target for creating the user manual (PDF version).
  312         manual_env.Manual(target='user_manual_pdf', source=None)
  313         manual_env.Depends('user_manual_pdf', 'manual_clean')
  314         manual_env.Depends('user_manual_pdf', 'manual_version_file')
  315         manual_env.Depends('user_manual_pdf', 'manual_copyright_file')
  316         manual_env.Depends('user_manual_pdf', 'replicate_title_check')
  317         manual_env.Depends('user_manual_pdf', 'fetch_docstrings')
  318         manual_env.Depends('user_manual_pdf', 'compile_user_manual_pdf')
  319 
  320         # Target for creating the user manual (PDF version, without fetching the docstrings).
  321         manual_env.Manual(target='user_manual_pdf_nofetch', source=None)
  322         manual_env.Depends('user_manual_pdf_nofetch', 'manual_clean')
  323         manual_env.Depends('user_manual_pdf_nofetch', 'manual_version_file')
  324         manual_env.Depends('user_manual_pdf_nofetch', 'manual_copyright_file')
  325         manual_env.Depends('user_manual_pdf_nofetch', 'replicate_title_check')
  326         manual_env.Depends('user_manual_pdf_nofetch', 'compile_user_manual_pdf')
  327 
  328         # Target for creating the user manual (HTML version).
  329         manual_env.Manual(target='user_manual_html', source=None)
  330         manual_env.Depends('user_manual_html', 'manual_clean')
  331         manual_env.Depends('user_manual_html', 'manual_version_file')
  332         manual_env.Depends('user_manual_html', 'manual_copyright_file')
  333         manual_env.Depends('user_manual_html', 'replicate_title_check')
  334         manual_env.Depends('user_manual_html', 'fetch_docstrings')
  335         manual_env.Depends('user_manual_html', 'compile_user_manual_html')
  336 
  337         # Target for creating the user manual (HTML version, without fetching the docstrings).
  338         manual_env.Manual(target='user_manual_html_nofetch', source=None)
  339         manual_env.Depends('user_manual_html_nofetch', 'manual_clean')
  340         manual_env.Depends('user_manual_html_nofetch', 'manual_version_file')
  341         manual_env.Depends('user_manual_html_nofetch', 'manual_copyright_file')
  342         manual_env.Depends('user_manual_html_nofetch', 'replicate_title_check')
  343         manual_env.Depends('user_manual_html_nofetch', 'compile_user_manual_html')
  344 
  345         # Target for creating the API documentation manual (HTML version).
  346         manual_env.Manual(target='api_manual_html', source=None)
  347         manual_env.Depends('api_manual_html', 'manual_clean')
  348         manual_env.Depends('api_manual_html', 'compile_api_manual_html')
  349 
  350 
  351         # Target for creating relax version number LaTeX file.
  352         manual_env.Append(BUILDERS={'Version' : Builder(action=version_file)})
  353         manual_env.Version(target='manual_version_file', source=None)
  354 
  355         # Target for creating relax copyright notice LaTeX file.
  356         manual_env.Append(BUILDERS={'Copyright' : Builder(action=copyright_file)})
  357         manual_env.Copyright(target='manual_copyright_file', source=None)
  358 
  359         # Target for checking for replicated titles.
  360         manual_env.Append(BUILDERS={'Replicate' : Builder(action=replicate_title_check)})
  361         manual_env.Replicate(target='replicate_title_check', source=None)
  362 
  363         # Target for fetching the docstrings.
  364         manual_env.Append(BUILDERS={'Fetch' : Builder(action=fetch_docstrings)})
  365         manual_env.Fetch(target='fetch_docstrings', source=None)
  366 
  367         # Target for compiling the PDF version of the user manual from the LaTeX sources.
  368         manual_env.Append(BUILDERS={'CompileUserManualPDF' : Builder(action=compile_user_manual_pdf)})
  369         manual_env.CompileUserManualPDF(target='compile_user_manual_pdf', source=None)
  370 
  371         # Target for compiling the HTML version of the user manual from the LaTeX sources.
  372         manual_env.Append(BUILDERS={'CompileUserManualHTML' : Builder(action=compile_user_manual_html)})
  373         manual_env.CompileUserManualHTML(target='compile_user_manual_html', source=None)
  374 
  375         # Target for compiling the HTML version of the API documentation manual using Epydoc.
  376         manual_env.Append(BUILDERS={'CompileAPIManualHTML' : Builder(action=compile_api_manual_html)})
  377         manual_env.CompileAPIManualHTML(target='compile_api_manual_html', source=None)
  378 
  379         # Clean target.
  380         manual_env.Append(BUILDERS={'Clean' : Builder(action=clean_manual_files)})
  381         manual_env.Clean(target='manual_clean', source=None)
  382 
  383         # Clean target (with no manual environments dependent on it).
  384         manual_env.Append(BUILDERS={'Clean' : Builder(action=clean_manual_files)})
  385         manual_env.Clean(target='manual_clean_nodeps', source=None)
  386 
  387 
  388     def clean_all_files(self, target, source, env):
  389         """Builder action for cleaning up."""
  390 
  391         # Print out.
  392         print
  393         print("#########################")
  394         print("# Cleaning up all files #")
  395         print("#########################\n\n")
  396 
  397         # Extensions of files to remove.
  398         temp_extns = ['so', 'sconsign', 'dll', 'pyd']
  399 
  400         # Print out.
  401         print("\nRemoving the files ending in %s.\n" % temp_extns)
  402 
  403         # Walk through the directories.
  404         for root, dirs, files in walk(getcwd()):
  405             # Loop over the files in the current directory.
  406             for file in files:
  407                 # Loop over the extensions.
  408                 for ext in temp_extns:
  409                     if search('\.' + ext + '$', file):
  410                         remove(path.join(root, file))
  411 
  412         # Remove build directories.
  413         if path.isdir('build'):
  414             print("Removing the build directory 'build' used to create a Mac OS X app.")
  415             rmtree('build')
  416         if path.isdir('dist'):
  417             print("Removing the distribution directory 'dist' used to create a Mac OS X app.")
  418             rmtree('dist')
  419 
  420         # Final printout.
  421         print("\n\n\n")
  422 
  423 
  424     def clean_files(self, target, source, env):
  425         """Builder action for removing temporary files."""
  426 
  427         # Print out.
  428         print
  429         print("###############################")
  430         print("# Cleaning up temporary files #")
  431         print("###############################\n\n")
  432 
  433         # Extensions of temporary files.
  434         temp_extns = ['pyc', 'pyo', 'bak', 'o', 'os', 'obj', 'exp', 'lib']
  435 
  436         # Print out.
  437         print("\nRemoving the files ending in %s.\n" % temp_extns)
  438 
  439         # Walk through the directories.
  440         for root, dirs, files in walk(getcwd()):
  441             # Loop over the files in the current directory.
  442             for file in files:
  443                 # Loop over the extensions.
  444                 for ext in temp_extns:
  445                     if search('\.' + ext + '$', file):
  446                         remove(path.join(root, file))
  447 
  448         # Remove relax save state files.
  449         print("Removing temporary relax save state files (of the form relax_state_xxxxxxxx_xxxxxx.bz2).\n")
  450         for root, dirs, files in walk(getcwd()):
  451             # Loop over the files in the current directory.
  452             for file in files:
  453                 if search('^relax_state_.*.bz2', file):
  454                     remove(path.join(root, file))
  455 
  456         # Remove the Python 3 __pycache__ directories.
  457         print("Removing the Python 3 __pycache__ directories.\n")
  458         for root, dirs, files in walk(getcwd()):
  459             # Loop over the directories.
  460             for dir in dirs:
  461                 if search('__pycache__', dir):
  462                     rmdir(path.join(root, dir))
  463 
  464 
  465         # Final printout.
  466         print("\n\n\n")
  467 
  468 
  469     def det_arch(self):
  470         """Determine which architectures are supported for cross-compilation on Mac OS X.
  471 
  472         @return:    The list of CPU architects to cross-compile.
  473         @rtype:     list of str
  474         """
  475 
  476         # Printout.
  477         print("\nDetermining which architectures can be cross compiled for.")
  478 
  479         # Create a temporary directory for compilation tests.
  480         tempdir = mkdtemp()
  481 
  482         # The list of archectures to try.
  483         archs = ['i386', 'ppc', 'x86_64', 'ppc64']
  484         allowed = []
  485 
  486         # Safely loop over each arch and test it.
  487         try:
  488             for arch in archs:
  489                 # Create a C file to compile.
  490                 base_name = tempdir + sep + 'test'
  491                 file = open(base_name + '.c', 'w')
  492                 file.write("#include<stdio.h>\n\n")
  493                 file.write("main() {\n")
  494                 file.write("    printf(\"Compilation with arch '%s' successful.\\n\");\n" % arch)
  495                 file.write("}\n")
  496                 file.close()
  497 
  498                 # Run gcc.
  499                 arch_test = ''
  500                 for name in allowed:
  501                     arch_test += '-arch %s ' % name
  502                 pipe = Popen('gcc %s -arch %s %s.c -o %s' % (arch_test, arch, base_name, base_name), shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=False)
  503                 for line in pipe.stdout.readlines():
  504                     pass
  505 
  506                 # Execute the file.
  507                 pipe = Popen('%s' % base_name, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=False)
  508 
  509                 # Check the output.
  510                 for line in pipe.stdout.readlines():
  511                     # Printout.
  512                     print("    %s" % line[:-1])
  513 
  514                     # Successful arch.
  515                     if search("successful", line.decode('ISO-8859-1')):
  516                         allowed.append(arch)
  517 
  518                 # Delete the compiled file, if it exists.
  519                 if access(base_name, F_OK):
  520                     remove(base_name)
  521 
  522         # Clean up.
  523         finally:
  524             rmtree(tempdir)
  525 
  526         # Return the list.
  527         print("\n")
  528         return allowed
  529 
  530 
  531     def dummy(self, target, source, env):
  532         """Dummy function which returns zero."""
  533 
  534         return 0
  535 
  536 
  537     def help(self):
  538         """The help message."""
  539 
  540         # Intro.
  541         target_format = "  %-25s%-40s\n"
  542         string = "\nHelp for using Scons to build the various components of relax.\n\n"
  543 
  544         # Usage message.
  545         string += "usage: scons [target]\n"
  546 
  547         # No target.
  548         string += "\nNo target:\n"
  549         string += "  %-25s\n" % ("Compile the C modules.")
  550 
  551         # Standard targets.
  552         string += "\nStandard targets:\n"
  553         string += target_format % ("install", "Install relax.")
  554         string += target_format % ("uninstall", "Uninstall relax.")
  555         string += target_format % ("binary_dist", "Create the binary distribution packages.")
  556         string += target_format % ("source_dist", "Create the source distribution packages.")
  557         string += target_format % ("clean", "Remove the temporary files.")
  558         string += target_format % ("clean_all", "Remove the compiled and temporary files.")
  559         string += target_format % ("user_manual_pdf", "Create the user manual (PDF version).")
  560         string += target_format % ("user_manual_pdf_nofetch", "Create the user manual (PDF version, without fetching the docstrings).")
  561         string += target_format % ("user_manual_html", "Create the user manual (HTML version).")
  562         string += target_format % ("user_manual_html_nofetch", "Create the user manual (HTML version, without fetching the docstrings).")
  563         string += target_format % ("api_manual_html", "Create the API documentation manual (HTML version).")
  564 
  565         # Specific targets.
  566         string += "\nSpecific targets:\n"
  567         string += target_format % ("package_bin", "Package the binary distribution.")
  568         string += target_format % ("package_src", "Package the source distribution.")
  569         string += target_format % ("gpg_bin", "GPG sign the binary distribution file.")
  570         string += target_format % ("gpg_src", "GPG sign the source distribution file.")
  571         string += target_format % ("version_check", "Check the relax version number.")
  572         string += target_format % ("manual_version_file", "Create the relax version number LaTeX file.")
  573         string += target_format % ("manual_copyright_file", "Create the LaTeX file containing the copyright notice.")
  574         string += target_format % ("replicate_title_check", "Check for replicated titles in the LaTeX sources.")
  575         string += target_format % ("fetch_docstrings", "Fetch and LaTeX format the docstrings.")
  576         string += target_format % ("compile_user_manual_pdf", "Compile the PDF version of the user manual from the LaTeX sources.")
  577         string += target_format % ("compile_user_manual_html", "Compile the HTML version of the user manual from the LaTeX sources.")
  578         string += target_format % ("compile_api_manual_html", "Compile the HTML version of the API documentation manual using Epydoc.")
  579         string += target_format % ("manual_clean", "Remove the temporary manual files.")
  580         string += target_format % ("manual_clean_nodeps", "Remove the temporary manual files (with no manual environments dependent on it).")
  581 
  582         # Environmental variables.
  583         string += "\nOptional environmental variables:\n"
  584         string += target_format % ("CC", "The compiler to use.")
  585         string += target_format % ("CFLAGS", "The compiler flags.")
  586         string += target_format % ("LDFLAGS", "The linker flags.")
  587         string += target_format % ("PYTHON_INCLUDE_DIR", "Manually specify where the version-specific 'Python.h' file is located.")
  588 
  589         # Set the help message.
  590         Help(string)
  591 
  592 
  593     def relax_fit(self):
  594         """Function for setting up scons for building the relaxation curve fitting C modules."""
  595 
  596         # The directory.
  597         dir = 'target_functions'
  598 
  599         # File names.
  600         files = ['c_chi2.c',
  601                  'exponential.c',
  602                  'exponential_inv.c',
  603                  'exponential_sat.c',
  604                  'relax_fit.c']
  605 
  606         # Construct the Python include path (for Python.h).
  607         py_include_fullpath = None
  608         py_include_minpath = path.join(sys.prefix, 'include')
  609         py_version = 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1])
  610         if access(path.join(py_include_minpath, py_version, 'Python.h'), F_OK):
  611             py_include_fullpath = path.join(py_include_minpath, py_version)
  612         elif access(path.join(py_include_minpath, py_version + 'm', 'Python.h'), F_OK):
  613             py_include_fullpath = path.join(py_include_minpath, py_version + 'm')
  614 
  615         # Test if 'PYTHON_INCLUDE_DIR' has been set to system environment.
  616         elif 'PYTHON_INCLUDE_DIR' in environ and access(path.join(environ['PYTHON_INCLUDE_DIR'], 'Python.h'), F_OK):
  617             py_include_fullpath = environ['PYTHON_INCLUDE_DIR']
  618 
  619         # Construct the python bin path.
  620         py_bin_minpath = sys.prefix + path.sep + 'bin'
  621         py_bin_fullpath = py_bin_minpath + path.sep + 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1])
  622 
  623         # Relaxation curve fitting build environment.
  624         env = Environment(TARGET_ARCH=TARGET_ARCH)
  625 
  626         # Determine the cross-compilation architectures for Mac systems.
  627         if env['PLATFORM'] == 'darwin':
  628             archs = self.det_arch()
  629 
  630         # C flags.
  631         if SYSTEM == 'Windows':
  632             cflags = '/nologo /I\"' + py_include_minpath + '\"'
  633         elif py_include_fullpath:
  634             cflags = '-I' + py_include_fullpath
  635         if env['PLATFORM'] == 'darwin':
  636             for arch in archs:
  637                 cflags += ' -arch %s' % arch
  638 
  639         # Python library path.
  640         libpath = ''
  641         if SYSTEM == 'Windows':
  642             libpath = sys.prefix + path.sep + 'libs'
  643 
  644         # Add the python library path to the environment.
  645         env.Append(LIBPATH = libpath)
  646 
  647         # Catch Mac OS X and send the correct command line options to the linker (these may become redundant as SCons improves).
  648         if env['PLATFORM'] == 'darwin':
  649             # The flags.
  650             lnflags = [
  651                 '-bundle',
  652                 '-bundle_loader', py_bin_fullpath,
  653                 '-dynamic',
  654                 '-undefined', 'dynamic_lookup'
  655             ]
  656 
  657             # Force all architectures.
  658             for arch in archs:
  659                 lnflags.append('-arch')
  660                 lnflags.append(arch)
  661 
  662             # Set up the environment.
  663             env.Append(LINKFLAGS = lnflags)
  664             env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS')
  665 
  666         # Shared library prefix and suffix.
  667         prefix = ''
  668         suffix = '.so'
  669         if SYSTEM == 'Windows':
  670             suffix = '.pyd'
  671 
  672         # Loop over the relaxation curve fitting files.
  673         nodes = []
  674         for file in files:
  675             nodes.append(env.SharedObject(dir + path.sep + file, CCFLAGS=cflags))
  676 
  677         # Respect the user environment, specifically compiler, compiler- and linkerflags.
  678         if 'LDFLAGS' in environ:
  679             env.Append(LINKFLAGS = environ['LDFLAGS'])
  680         if 'CFLAGS' in environ:
  681             env.Append(CFLAGS = environ['CFLAGS'])
  682         if 'CC' in environ:
  683             env.Replace(CC = environ['CC'])
  684 
  685         # Build the relaxation curve fitting module.
  686         self.relax_fit_object = env.SharedLibrary(target=dir + path.sep + 'relax_fit', source=nodes, SHLIBPREFIX=prefix, SHLIBSUFFIX=suffix)
  687 
  688         # Print out string returning function.
  689         def print_string(target, source, env):
  690             string = "\n\n\n\n"
  691             string += "###########################\n"
  692             string += "# Compiling the C modules #\n"
  693             string += "###########################\n\n\n"
  694             string += "Building the relaxation curve fitting module '%s'.\n" % self.relax_fit_object[0]
  695             if SYSTEM == 'Windows':
  696                 string += "MS Windows target arch: %s\n" % TARGET_ARCH
  697             return string
  698 
  699         # Add the printout as an action to take before constructing the first object.
  700         env.AddPreAction(nodes[0], Action(self.dummy, print_string))
  701 
  702 
  703     def test_version(self, target, source, env):
  704         """Builder action for testing that the program version number has been set."""
  705 
  706         # Print out.
  707         print
  708         print("#######################################")
  709         print("# Checking the program version number #")
  710         print("#######################################\n\n")
  711         print("Version number: %s\n" % version)
  712 
  713         # Test.
  714         if version == "repository commit":
  715             sys.stderr.write("The program version number has not been set.\n\n")
  716             sys.exit()
  717 
  718         # Final printout.
  719         print("\n\n\n")
  720 
  721 
  722 # Execute the main class.
  723 if __name__ in ['__main__', 'SCons.Script']:
  724     Main()