SConscript (9449B)
1 import os.path, copy, sys 2 3 def checkSymbol(conf, header, library=None, symbol=None, autoAdd=True, critical=False, pkgName=None): 4 """ Check for symbol in library, optionally look only for header. 5 @param conf: Configure instance. 6 @param header: The header file where the symbol is declared. 7 @param library: The library in which the symbol exists, if None it is taken to be the standard C library. 8 @param symbol: The symbol to look for, if None only the header will be looked up. 9 @param autoAdd: Automatically link with this library if check is positive. 10 @param critical: Raise on error? 11 @param pkgName: Optional name of pkg-config entry for library, to determine build parameters. 12 @return: True/False 13 """ 14 origEnv = conf.env.Copy() # Copy unmodified environment so we can restore it upon error 15 env = conf.env 16 if library is None: 17 library = "c" # Standard library 18 autoAdd = False 19 20 if pkgName is not None: 21 origLibs = copy.copy(env.get("LIBS", None)) 22 23 try: env.ParseConfig("pkg-config --silence-errors %s --cflags --libs" % pkgName) 24 except: pass 25 else: 26 # I see no other way of checking that the parsing succeeded, if it did add no more linking parameters 27 if env.get("LIBS", None) != origLibs: 28 autoAdd = False 29 30 try: 31 if not conf.CheckCHeader(header, include_quotes="<>"): 32 raise ConfigurationError("missing header %s" % header) 33 if symbol is not None and not conf.CheckLib(library, symbol, language="C", autoadd=autoAdd): 34 raise ConfigurationError("missing symbol %s in library %s" % (symbol, library)) 35 except ConfigurationError: 36 conf.env = origEnv 37 if not critical: 38 return False 39 raise 40 41 return True 42 43 import SCons.Errors 44 45 # Import common variables 46 47 # Could use '#' to refer to top-level SConstruct directory, but looks like env.SConsignFile doesn't interpret this at least :( 48 sconsDir = os.path.abspath(os.path.join("build", "scons")) 49 50 try: 51 Import("Platform", "Posix", "ConfigurationError", "ApiVer") 52 except SCons.Errors.UserError: 53 # The common objects must be exported first 54 SConscript(os.path.join(sconsDir, "SConscript_common")) 55 Import("Platform", "Posix", "ConfigurationError", "ApiVer") 56 57 Import("env") 58 59 # This will be manipulated 60 env = env.Copy() 61 62 # We operate with a set of needed libraries and optional libraries, the latter stemming from host API implementations. 63 # For libraries of both types we record a set of values that is used to look for the library in question, during 64 # configuration. If the corresponding library for a host API implementation isn't found, the implementation is left out. 65 neededLibs = [] 66 optionalImpls = {} 67 if Platform in Posix: 68 env.Append(CPPPATH=os.path.join("os", "unix")) 69 neededLibs += [("pthread", "pthread.h", "pthread_create"), ("m", "math.h", "sin")] 70 if env["useALSA"]: 71 optionalImpls["ALSA"] = ("asound", "alsa/asoundlib.h", "snd_pcm_open") 72 if env["useJACK"]: 73 optionalImpls["JACK"] = ("jack", "jack/jack.h", "jack_client_new") 74 if env["useOSS"]: 75 # TODO: It looks like the prefix for soundcard.h depends on the platform 76 optionalImpls["OSS"] = ("oss", "sys/soundcard.h", None) 77 if Platform == 'netbsd': 78 optionalImpls["OSS"] = ("ossaudio", "sys/soundcard.h", "_oss_ioctl") 79 if env["useASIHPI"]: 80 optionalImpls["ASIHPI"] = ("hpi", "asihpi/hpi.h", "HPI_SubSysCreate") 81 if env["useCOREAUDIO"]: 82 optionalImpls["COREAUDIO"] = ("CoreAudio", "CoreAudio/CoreAudio.h", None) 83 else: 84 raise ConfigurationError("unknown platform %s" % Platform) 85 86 if Platform == "darwin": 87 env.Append(LINKFLAGS="-framework CoreFoundation -framework CoreServices -framework CoreAudio -framework AudioToolBox -framework AudioUnit") 88 elif Platform == "cygwin": 89 env.Append(LIBS=["winmm"]) 90 elif Platform == "irix": 91 neededLibs += [("audio", "dmedia/audio.h", "alOpenPort"), ("dmedia", "dmedia/dmedia.h", "dmGetUST")] 92 env.Append(CPPDEFINES=["PA_USE_SGI"]) 93 94 def CheckCTypeSize(context, tp): 95 """ Check size of C type. 96 @param context: A configuration context. 97 @param tp: The type to check. 98 @return: Size of type, in bytes. 99 """ 100 context.Message("Checking the size of C type %s..." % tp) 101 ret = context.TryRun(""" 102 #include <stdio.h> 103 104 int main() { 105 printf("%%d", sizeof(%s)); 106 return 0; 107 } 108 """ % tp, ".c") 109 if not ret[0]: 110 context.Result(" Couldn't obtain size of type %s!" % tp) 111 return None 112 113 assert ret[1] 114 sz = int(ret[1]) 115 context.Result("%d" % sz) 116 return sz 117 118 """ 119 if sys.byteorder == "little": 120 env.Append(CPPDEFINES=["PA_LITTLE_ENDIAN"]) 121 elif sys.byteorder == "big": 122 env.Append(CPPDEFINES=["PA_BIG_ENDIAN"]) 123 else: 124 raise ConfigurationError("unknown byte order: %s" % sys.byteorder) 125 """ 126 if env["enableDebugOutput"]: 127 env.Append(CPPDEFINES=["PA_ENABLE_DEBUG_OUTPUT"]) 128 129 # Start configuration 130 131 # Use an absolute path for conf_dir, otherwise it gets created both relative to current directory and build directory 132 conf = env.Configure(log_file=os.path.join(sconsDir, "sconf.log"), custom_tests={"CheckCTypeSize": CheckCTypeSize}, 133 conf_dir=os.path.join(sconsDir, ".sconf_temp")) 134 conf.env.Append(CPPDEFINES=["SIZEOF_SHORT=%d" % conf.CheckCTypeSize("short")]) 135 conf.env.Append(CPPDEFINES=["SIZEOF_INT=%d" % conf.CheckCTypeSize("int")]) 136 conf.env.Append(CPPDEFINES=["SIZEOF_LONG=%d" % conf.CheckCTypeSize("long")]) 137 if checkSymbol(conf, "time.h", "rt", "clock_gettime"): 138 conf.env.Append(CPPDEFINES=["HAVE_CLOCK_GETTIME"]) 139 if checkSymbol(conf, "time.h", symbol="nanosleep"): 140 conf.env.Append(CPPDEFINES=["HAVE_NANOSLEEP"]) 141 if conf.CheckCHeader("sys/soundcard.h"): 142 conf.env.Append(CPPDEFINES=["HAVE_SYS_SOUNDCARD_H"]) 143 if conf.CheckCHeader("linux/soundcard.h"): 144 conf.env.Append(CPPDEFINES=["HAVE_LINUX_SOUNDCARD_H"]) 145 if conf.CheckCHeader("machine/soundcard.h"): 146 conf.env.Append(CPPDEFINES=["HAVE_MACHINE_SOUNDCARD_H"]) 147 148 # Look for needed libraries and link with them 149 for lib, hdr, sym in neededLibs: 150 checkSymbol(conf, hdr, lib, sym, critical=True) 151 # Look for host API libraries, if a library isn't found disable corresponding host API implementation. 152 for name, val in optionalImpls.items(): 153 lib, hdr, sym = val 154 if checkSymbol(conf, hdr, lib, sym, critical=False, pkgName=name.lower()): 155 conf.env.Append(CPPDEFINES=["PA_USE_%s=1" % name.upper()]) 156 else: 157 del optionalImpls[name] 158 159 # Configuration finished 160 env = conf.Finish() 161 162 # PA infrastructure 163 CommonSources = [os.path.join("common", f) for f in "pa_allocation.c pa_converters.c pa_cpuload.c pa_dither.c pa_front.c \ 164 pa_process.c pa_stream.c pa_trace.c pa_debugprint.c pa_ringbuffer.c".split()] 165 CommonSources.append(os.path.join("hostapi", "skeleton", "pa_hostapi_skeleton.c")) 166 167 # Host APIs implementations 168 ImplSources = [] 169 if Platform in Posix: 170 ImplSources += [os.path.join("os", "unix", f) for f in "pa_unix_hostapis.c pa_unix_util.c".split()] 171 172 if "ALSA" in optionalImpls: 173 ImplSources.append(os.path.join("hostapi", "alsa", "pa_linux_alsa.c")) 174 if "JACK" in optionalImpls: 175 ImplSources.append(os.path.join("hostapi", "jack", "pa_jack.c")) 176 if "OSS" in optionalImpls: 177 ImplSources.append(os.path.join("hostapi", "oss", "pa_unix_oss.c")) 178 if "ASIHPI" in optionalImpls: 179 ImplSources.append(os.path.join("hostapi", "asihpi", "pa_linux_asihpi.c")) 180 if "COREAUDIO" in optionalImpls: 181 ImplSources.append([os.path.join("hostapi", "coreaudio", f) for f in """ 182 pa_mac_core.c pa_mac_core_blocking.c pa_mac_core_utilities.c 183 """.split()]) 184 185 186 sources = CommonSources + ImplSources 187 188 sharedLibEnv = env.Copy() 189 if Platform in Posix: 190 # Add soname to library, this is so a reference is made to the versioned library in programs linking against libportaudio.so 191 if Platform != 'darwin': 192 sharedLibEnv.AppendUnique(SHLINKFLAGS="-Wl,-soname=libportaudio.so.%d" % int(ApiVer.split(".")[0])) 193 sharedLib = sharedLibEnv.SharedLibrary(target="portaudio", source=sources) 194 195 staticLib = env.StaticLibrary(target="portaudio", source=sources) 196 197 if Platform in Posix: 198 prefix = env["prefix"] 199 includeDir = os.path.join(prefix, "include") 200 libDir = os.path.join(prefix, "lib") 201 202 testNames = ["patest_sine", "paqa_devs", "paqa_errs", "patest1", "patest_buffer", "patest_callbackstop", "patest_clip", \ 203 "patest_dither", "patest_hang", "patest_in_overflow", "patest_latency", "patest_leftright", "patest_longsine", \ 204 "patest_many", "patest_maxsines", "patest_multi_sine", "patest_out_underflow", "patest_pink", "patest_prime", \ 205 "patest_read_record", "patest_record", "patest_ringmix", "patest_saw", "patest_sine8", "patest_sine", \ 206 "patest_sine_time", "patest_start_stop", "patest_stop", "patest_sync", "patest_toomanysines", \ 207 "patest_underflow", "patest_wire", "patest_write_sine", "pa_devs", "pa_fuzz", "pa_minlat", \ 208 "patest_sine_channelmaps",] 209 210 # The test directory ("bin") should be in the top-level PA directory 211 tests = [env.Program(target=os.path.join("#", "bin", name), source=[os.path.join("#", "test", name + ".c"), 212 staticLib]) for name in testNames] 213 214 # Detect host APIs 215 hostApis = [] 216 for cppdef in env["CPPDEFINES"]: 217 if cppdef.startswith("PA_USE_"): 218 hostApis.append(cppdef[7:-2]) 219 220 Return("sources", "sharedLib", "staticLib", "tests", "env", "hostApis")