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_skeleton.c pa_stream.c pa_trace.c pa_debugprint.c pa_ringbuffer.c".split()] |
165 |
|
166 |
# Host APIs implementations |
167 |
ImplSources = [] |
168 |
if Platform in Posix: |
169 |
ImplSources += [os.path.join("os", "unix", f) for f in "pa_unix_hostapis.c pa_unix_util.c".split()] |
170 |
|
171 |
if "ALSA" in optionalImpls: |
172 |
ImplSources.append(os.path.join("hostapi", "alsa", "pa_linux_alsa.c")) |
173 |
if "JACK" in optionalImpls: |
174 |
ImplSources.append(os.path.join("hostapi", "jack", "pa_jack.c")) |
175 |
if "OSS" in optionalImpls: |
176 |
ImplSources.append(os.path.join("hostapi", "oss", "pa_unix_oss.c")) |
177 |
if "ASIHPI" in optionalImpls: |
178 |
ImplSources.append(os.path.join("hostapi", "asihpi", "pa_linux_asihpi.c")) |
179 |
if "COREAUDIO" in optionalImpls: |
180 |
ImplSources.append([os.path.join("hostapi", "coreaudio", f) for f in """ |
181 |
pa_mac_core.c pa_mac_core_blocking.c pa_mac_core_utilities.c |
182 |
""".split()]) |
183 |
|
184 |
|
185 |
sources = CommonSources + ImplSources |
186 |
|
187 |
sharedLibEnv = env.Copy() |
188 |
if Platform in Posix: |
189 |
# Add soname to library, this is so a reference is made to the versioned library in programs linking against libportaudio.so |
190 |
if Platform != 'darwin': |
191 |
sharedLibEnv.AppendUnique(SHLINKFLAGS="-Wl,-soname=libportaudio.so.%d" % int(ApiVer.split(".")[0])) |
192 |
sharedLib = sharedLibEnv.SharedLibrary(target="portaudio", source=sources) |
193 |
|
194 |
staticLib = env.StaticLibrary(target="portaudio", source=sources) |
195 |
|
196 |
if Platform in Posix: |
197 |
prefix = env["prefix"] |
198 |
includeDir = os.path.join(prefix, "include") |
199 |
libDir = os.path.join(prefix, "lib") |
200 |
|
201 |
testNames = ["patest_sine", "paqa_devs", "paqa_errs", "patest1", "patest_buffer", "patest_callbackstop", "patest_clip", \ |
202 |
"patest_dither", "patest_hang", "patest_in_overflow", "patest_latency", "patest_leftright", "patest_longsine", \ |
203 |
"patest_many", "patest_maxsines", "patest_multi_sine", "patest_out_underflow", "patest_pink", "patest_prime", \ |
204 |
"patest_read_record", "patest_record", "patest_ringmix", "patest_saw", "patest_sine8", "patest_sine", \ |
205 |
"patest_sine_time", "patest_start_stop", "patest_stop", "patest_sync", "patest_toomanysines", \ |
206 |
"patest_underflow", "patest_wire", "patest_write_sine", "pa_devs", "pa_fuzz", "pa_minlat", \ |
207 |
"patest_sine_channelmaps",] |
208 |
|
209 |
# The test directory ("bin") should be in the top-level PA directory |
210 |
tests = [env.Program(target=os.path.join("#", "bin", name), source=[os.path.join("#", "test", name + ".c"), |
211 |
staticLib]) for name in testNames] |
212 |
|
213 |
# Detect host APIs |
214 |
hostApis = [] |
215 |
for cppdef in env["CPPDEFINES"]: |
216 |
if cppdef.startswith("PA_USE_"): |
217 |
hostApis.append(cppdef[7:-2]) |
218 |
|
219 |
Return("sources", "sharedLib", "staticLib", "tests", "env", "hostApis") |