from __future__ import print_function from __future__ import absolute_import from __future__ import division import os import glob import subprocess from distutils import sysconfig from SCons.Errors import BuildError from SCons.Environment import Environment # Useful constants try: RATROOT = os.environ["RATROOT"] except KeyError: RATROOT = "" RATCONFIGDIR = os.path.join(RATROOT, "config") RATENVFILE = os.path.join(RATCONFIGDIR, "RAT.scons") PSQLENVFILE = os.path.join(RATCONFIGDIR, "PSQL.scons") try: ROOTSYS = os.path.join(os.environ["ROOTSYS"], 'bin') except KeyError: ROOTSYS = "" try: rootarch_cmd = [os.path.join(ROOTSYS, "root-config"), "--arch"] p_ra = subprocess.Popen(rootarch_cmd, universal_newlines=True, stdout=subprocess.PIPE) ROOTARCH = p_ra.communicate()[0].strip() except OSError: # If architecture cannot be extracted, use generic GCC default. ROOTARCH = "gcc" def testenv(envname): ''' Test for the presence of an environment var and if it set to 1. ''' return envname in os.environ and os.environ[envname] == '1' def rat_path(*args): ''' Returns the canonical path to join(RATROOT, *args) by eliminating any symbolic links encountered in the path. Without this, scons will rebuild everything when compiling over NFS. ''' return os.path.realpath(os.path.join(RATROOT, *args)) def build_list(srcpath, build_dir, exclude=()): ''' Construct a list of build targets from a source path. ''' # Get all files in the src path, excluding desired files. l = [os.path.join(build_dir, os.path.basename(item)) for item in glob.glob(srcpath) if os.path.basename(item) not in exclude] # Add Version.cc manually since this is called before the scons target is built. if build_dir.split(os.sep)[-1] == 'core': l.append(os.path.join(build_dir, 'Version.cc')) # Remove duplicate entries, if any, and sort the list. # This is to prevent unnecessary rebuilds. l = list(set(l)) l.sort() return l def src_module(env, module_name, header_subdir="", exclude=()): ''' Create targets from a source directory, and add headers to the build list. ''' modbuilddir = os.path.join(env['BUILDDIR'], module_name) srcdir = os.path.join('src', module_name) env.VariantDir(modbuilddir, srcdir, duplicate=0) # 09-Aug-2006 WGS: Add a "builder" for the headers so that only # those headers that are needed or revised are copied. headers = glob.glob(srcdir + '/*.hh') + \ glob.glob(srcdir + '/*.hpp') + \ glob.glob(srcdir + '/*.tpp') + \ glob.glob(srcdir + '/*.icc') + \ glob.glob(srcdir + '/*.h') # Create a separate environment for copying the header files. # This ensures that the file is only copied if it changes. # If any dependencies change, since there is no path to search, # the header file will NOT be recopied (as happened before). env_builder = Environment() env_builder['BUILDERS'] = env['BUILDERS'] env_builder['INCLUDE_SUBDIR'] = header_subdir for h in headers: if os.path.basename(h) not in exclude: env.Append(RATHEADERS=env_builder.RATHeader(h)) return env.Object(build_list(os.path.join(srcdir, '*.cc'), modbuilddir, exclude=exclude)) def src_psql(env): ''' Creates targets for PSQL. ''' assert 'PSQLSRCDIR' in env assert 'PSQLDEFINES' in env assert 'PSQLMODBUILDIR' in env assert 'PSQLINCSUBDIRS' in env srcdir = env['PSQLSRCDIR'] srclist = glob.glob(os.path.join(srcdir, '*.c')) local_defines = env['PSQLDEFINES'] if 'USE_REPL_SNPRINTF' not in local_defines: for entry in srclist: if os.path.basename(entry) == 'snprintf.c': srclist.remove(entry) if 'HAVE_GETPEEREID' in local_defines: for entry in srclist: if os.path.basename(entry) == 'getpeereid.c': srclist.remove(entry) # If this define exists, remove the source from the list if 'HAVE_DECL_STRLCPY' in local_defines: for entry in srclist: if os.path.basename(entry) == 'strlcpy.c': srclist.remove(entry) # If this define exists, remove the source from the list if 'HAVE_DECL_STRLCAT' in local_defines: for entry in srclist: if os.path.basename(entry) == 'strlcat.c': srclist.remove(entry) env.VariantDir(env['PSQLMODBUILDIR'], srcdir, duplicate=0) headers = glob.glob(srcdir + '/include/*.h') for sdir in env['PSQLINCSUBDIRS']: headers += glob.glob(srcdir + '/include/' + sdir + '/*.h') # Now attach the ta proper # Just Force copy the object into the include directory for h in headers: split_dir = str(h).split('/')[3:] if len(split_dir) > 1: env.Append(PSQLHEADERS=env.Install('/'.join(['#/include/libpq'] + split_dir[:-1]), h)) else: env.Append(PSQLHEADERS=env.Install('#/include/libpq', h)) env.Append(PSQLSRCS=env.Object([os.path.join(env['PSQLMODBUILDIR'], os.path.basename(item)) for item in srclist])) def check_and_parse_config(env, config_command, current_file): ''' Given a SCons environment, attempt to parse a config command. ''' config_exec = env.WhereIs(config_command[0]) if config_exec is None: print("scons: FATAL ERROR ({}).".format(current_file)) print("scons: Couldn't find {} in path.".format(config_command[0])) error = BuildError() error.errstr = "Couldn't find {} in path.".format(config_command[0]) error.filename = "{}".format(current_file) error.status = 2 error.exitstatus = 2 raise error env.ParseConfig(config_command) def get_version(config_command): ''' Get the version number from config. ''' command_list = [config_command, "--version"] p_v = subprocess.Popen(command_list, universal_newlines=True, stdout=subprocess.PIPE) version = p_v.communicate()[0].strip() return version def find_python_locations(): ''' Get various properties of the Python distribution being used. Includes version, architecture, and library. ''' headers = sysconfig.get_python_inc() libs = sysconfig.get_config_var("LIBDIR") arch = sysconfig.get_config_var('MULTIARCH') version = sysconfig.get_python_version() ldlibrary = sysconfig.get_config_var('LDLIBRARY') return headers, libs, arch, version, ldlibrary