Chris@4
|
1 import sys, os.path
|
Chris@4
|
2
|
Chris@4
|
3 def rsplit(toSplit, sub, max=-1):
|
Chris@4
|
4 """ str.rsplit seems to have been introduced in 2.4 :( """
|
Chris@4
|
5 l = []
|
Chris@4
|
6 i = 0
|
Chris@4
|
7 while i != max:
|
Chris@4
|
8 try: idx = toSplit.rindex(sub)
|
Chris@4
|
9 except ValueError: break
|
Chris@4
|
10
|
Chris@4
|
11 toSplit, splitOff = toSplit[:idx], toSplit[idx + len(sub):]
|
Chris@4
|
12 l.insert(0, splitOff)
|
Chris@4
|
13 i += 1
|
Chris@4
|
14
|
Chris@4
|
15 l.insert(0, toSplit)
|
Chris@4
|
16 return l
|
Chris@4
|
17
|
Chris@4
|
18 sconsDir = os.path.join("build", "scons")
|
Chris@4
|
19 SConscript(os.path.join(sconsDir, "SConscript_common"))
|
Chris@4
|
20 Import("Platform", "Posix", "ApiVer")
|
Chris@4
|
21
|
Chris@4
|
22 # SConscript_opts exports PortAudio options
|
Chris@4
|
23 optsDict = SConscript(os.path.join(sconsDir, "SConscript_opts"))
|
Chris@4
|
24 optionsCache = os.path.join(sconsDir, "options.cache") # Save options between runs in this cache
|
Chris@4
|
25 options = Options(optionsCache, args=ARGUMENTS)
|
Chris@4
|
26 for k in ("Installation Dirs", "Build Targets", "Host APIs", "Build Parameters", "Bindings"):
|
Chris@4
|
27 options.AddOptions(*optsDict[k])
|
Chris@4
|
28 # Propagate options into environment
|
Chris@4
|
29 env = Environment(options=options)
|
Chris@4
|
30 # Save options for next run
|
Chris@4
|
31 options.Save(optionsCache, env)
|
Chris@4
|
32 # Generate help text for options
|
Chris@4
|
33 env.Help(options.GenerateHelpText(env))
|
Chris@4
|
34
|
Chris@4
|
35 buildDir = os.path.join("#", sconsDir, env["PLATFORM"])
|
Chris@4
|
36
|
Chris@4
|
37 # Determine parameters to build tools
|
Chris@4
|
38 if Platform in Posix:
|
Chris@4
|
39 threadCFlags = ''
|
Chris@4
|
40 if Platform != 'darwin':
|
Chris@4
|
41 threadCFlags = "-pthread "
|
Chris@4
|
42 baseLinkFlags = threadCFlags
|
Chris@4
|
43 baseCxxFlags = baseCFlags = "-Wall -pedantic -pipe " + threadCFlags
|
Chris@4
|
44 debugCxxFlags = debugCFlags = "-g"
|
Chris@4
|
45 optCxxFlags = optCFlags = "-O2"
|
Chris@4
|
46 env.Append(CCFLAGS = baseCFlags)
|
Chris@4
|
47 env.Append(CXXFLAGS = baseCxxFlags)
|
Chris@4
|
48 env.Append(LINKFLAGS = baseLinkFlags)
|
Chris@4
|
49 if env["enableDebug"]:
|
Chris@4
|
50 env.AppendUnique(CCFLAGS=debugCFlags.split())
|
Chris@4
|
51 env.AppendUnique(CXXFLAGS=debugCxxFlags.split())
|
Chris@4
|
52 if env["enableOptimize"]:
|
Chris@4
|
53 env.AppendUnique(CCFLAGS=optCFlags.split())
|
Chris@4
|
54 env.AppendUnique(CXXFLAGS=optCxxFlags.split())
|
Chris@4
|
55 if not env["enableAsserts"]:
|
Chris@4
|
56 env.AppendUnique(CPPDEFINES=["-DNDEBUG"])
|
Chris@4
|
57 if env["customCFlags"]:
|
Chris@4
|
58 env.Append(CCFLAGS=Split(env["customCFlags"]))
|
Chris@4
|
59 if env["customCxxFlags"]:
|
Chris@4
|
60 env.Append(CXXFLAGS=Split(env["customCxxFlags"]))
|
Chris@4
|
61 if env["customLinkFlags"]:
|
Chris@4
|
62 env.Append(LINKFLAGS=Split(env["customLinkFlags"]))
|
Chris@4
|
63
|
Chris@4
|
64 env.Append(CPPPATH=[os.path.join("#", "include"), "common"])
|
Chris@4
|
65
|
Chris@4
|
66 # Store all signatures in one file, otherwise .sconsign files will get installed along with our own files
|
Chris@4
|
67 env.SConsignFile(os.path.join(sconsDir, ".sconsign"))
|
Chris@4
|
68
|
Chris@4
|
69 env.SConscriptChdir(False)
|
Chris@4
|
70 sources, sharedLib, staticLib, tests, portEnv, hostApis = env.SConscript(os.path.join("src", "SConscript"),
|
Chris@4
|
71 build_dir=buildDir, duplicate=False, exports=["env"])
|
Chris@4
|
72
|
Chris@4
|
73 if Platform in Posix:
|
Chris@4
|
74 prefix = env["prefix"]
|
Chris@4
|
75 includeDir = os.path.join(prefix, "include")
|
Chris@4
|
76 libDir = os.path.join(prefix, "lib")
|
Chris@4
|
77 env.Alias("install", includeDir)
|
Chris@4
|
78 env.Alias("install", libDir)
|
Chris@4
|
79
|
Chris@4
|
80 # pkg-config
|
Chris@4
|
81
|
Chris@4
|
82 def installPkgconfig(env, target, source):
|
Chris@4
|
83 tgt = str(target[0])
|
Chris@4
|
84 src = str(source[0])
|
Chris@4
|
85 f = open(src)
|
Chris@4
|
86 try: txt = f.read()
|
Chris@4
|
87 finally: f.close()
|
Chris@4
|
88 txt = txt.replace("@prefix@", prefix)
|
Chris@4
|
89 txt = txt.replace("@exec_prefix@", prefix)
|
Chris@4
|
90 txt = txt.replace("@libdir@", libDir)
|
Chris@4
|
91 txt = txt.replace("@includedir@", includeDir)
|
Chris@4
|
92 txt = txt.replace("@LIBS@", " ".join(["-l%s" % l for l in portEnv["LIBS"]]))
|
Chris@4
|
93 txt = txt.replace("@THREAD_CFLAGS@", threadCFlags)
|
Chris@4
|
94
|
Chris@4
|
95 f = open(tgt, "w")
|
Chris@4
|
96 try: f.write(txt)
|
Chris@4
|
97 finally: f.close()
|
Chris@4
|
98
|
Chris@4
|
99 pkgconfigTgt = "portaudio-%d.0.pc" % int(ApiVer.split(".", 1)[0])
|
Chris@4
|
100 env.Command(os.path.join(libDir, "pkgconfig", pkgconfigTgt),
|
Chris@4
|
101 os.path.join("#", pkgconfigTgt + ".in"), installPkgconfig)
|
Chris@4
|
102
|
Chris@4
|
103 # Default to None, since if the user disables all targets and no Default is set, all targets
|
Chris@4
|
104 # are built by default
|
Chris@4
|
105 env.Default(None)
|
Chris@4
|
106 if env["enableTests"]:
|
Chris@4
|
107 env.Default(tests)
|
Chris@4
|
108 if env["enableShared"]:
|
Chris@4
|
109 env.Default(sharedLib)
|
Chris@4
|
110
|
Chris@4
|
111 if Platform in Posix:
|
Chris@4
|
112 def symlink(env, target, source):
|
Chris@4
|
113 trgt = str(target[0])
|
Chris@4
|
114 src = str(source[0])
|
Chris@4
|
115
|
Chris@4
|
116 if os.path.islink(trgt) or os.path.exists(trgt):
|
Chris@4
|
117 os.remove(trgt)
|
Chris@4
|
118 os.symlink(os.path.basename(src), trgt)
|
Chris@4
|
119
|
Chris@4
|
120 major, minor, micro = [int(c) for c in ApiVer.split(".")]
|
Chris@4
|
121
|
Chris@4
|
122 soFile = "%s.%s" % (os.path.basename(str(sharedLib[0])), ApiVer)
|
Chris@4
|
123 env.InstallAs(target=os.path.join(libDir, soFile), source=sharedLib)
|
Chris@4
|
124 # Install symlinks
|
Chris@4
|
125 symTrgt = os.path.join(libDir, soFile)
|
Chris@4
|
126 env.Command(os.path.join(libDir, "libportaudio.so.%d.%d" % (major, minor)),
|
Chris@4
|
127 symTrgt, symlink)
|
Chris@4
|
128 symTrgt = rsplit(symTrgt, ".", 1)[0]
|
Chris@4
|
129 env.Command(os.path.join(libDir, "libportaudio.so.%d" % major), symTrgt, symlink)
|
Chris@4
|
130 symTrgt = rsplit(symTrgt, ".", 1)[0]
|
Chris@4
|
131 env.Command(os.path.join(libDir, "libportaudio.so"), symTrgt, symlink)
|
Chris@4
|
132
|
Chris@4
|
133 if env["enableStatic"]:
|
Chris@4
|
134 env.Default(staticLib)
|
Chris@4
|
135 env.Install(libDir, staticLib)
|
Chris@4
|
136
|
Chris@4
|
137 env.Install(includeDir, os.path.join("include", "portaudio.h"))
|
Chris@4
|
138
|
Chris@4
|
139
|
Chris@4
|
140 if env["enableCxx"]:
|
Chris@4
|
141 env.SConscriptChdir(True)
|
Chris@4
|
142 cxxEnv = env.Copy()
|
Chris@4
|
143 sharedLibs, staticLibs, headers = env.SConscript(os.path.join("bindings", "cpp", "SConscript"),
|
Chris@4
|
144 exports={"env": cxxEnv, "buildDir": buildDir}, build_dir=os.path.join(buildDir, "portaudiocpp"), duplicate=False)
|
Chris@4
|
145 if env["enableStatic"]:
|
Chris@4
|
146 env.Default(staticLibs)
|
Chris@4
|
147 env.Install(libDir, staticLibs)
|
Chris@4
|
148 if env["enableShared"]:
|
Chris@4
|
149 env.Default(sharedLibs)
|
Chris@4
|
150 env.Install(libDir, sharedLibs)
|
Chris@4
|
151 env.Install(os.path.join(includeDir, "portaudiocpp"), headers)
|
Chris@4
|
152
|
Chris@4
|
153 # Generate portaudio_config.h header with compile-time definitions of which PA
|
Chris@4
|
154 # back-ends are available, and which includes back-end extension headers
|
Chris@4
|
155
|
Chris@4
|
156 # Host-specific headers
|
Chris@4
|
157 hostApiHeaders = {"ALSA": "pa_linux_alsa.h",
|
Chris@4
|
158 "ASIO": "pa_asio.h",
|
Chris@4
|
159 "COREAUDIO": "pa_mac_core.h",
|
Chris@4
|
160 "JACK": "pa_jack.h",
|
Chris@4
|
161 "WMME": "pa_winwmme.h",
|
Chris@4
|
162 }
|
Chris@4
|
163
|
Chris@4
|
164 def buildConfigH(target, source, env):
|
Chris@4
|
165 """builder for portaudio_config.h"""
|
Chris@4
|
166 global hostApiHeaders, hostApis
|
Chris@4
|
167 out = ""
|
Chris@4
|
168 for hostApi in hostApis:
|
Chris@4
|
169 out += "#define PA_HAVE_%s\n" % hostApi
|
Chris@4
|
170
|
Chris@4
|
171 hostApiSpecificHeader = hostApiHeaders.get(hostApi, None)
|
Chris@4
|
172 if hostApiSpecificHeader:
|
Chris@4
|
173 out += "#include \"%s\"\n" % hostApiSpecificHeader
|
Chris@4
|
174
|
Chris@4
|
175 out += "\n"
|
Chris@4
|
176 # Strip the last newline
|
Chris@4
|
177 if out and out[-1] == "\n":
|
Chris@4
|
178 out = out[:-1]
|
Chris@4
|
179
|
Chris@4
|
180 f = file(str(target[0]), 'w')
|
Chris@4
|
181 try: f.write(out)
|
Chris@4
|
182 finally: f.close()
|
Chris@4
|
183 return 0
|
Chris@4
|
184
|
Chris@4
|
185 # Define the builder for the config header
|
Chris@4
|
186 env.Append(BUILDERS={"portaudioConfig": env.Builder(
|
Chris@4
|
187 action=Action(buildConfigH), target_factory=env.fs.File)})
|
Chris@4
|
188
|
Chris@4
|
189 confH = env.portaudioConfig(File("portaudio_config.h", "include"),
|
Chris@4
|
190 File("portaudio.h", "include"))
|
Chris@4
|
191 env.Default(confH)
|
Chris@4
|
192 env.Install(os.path.join(includeDir, "portaudio"), confH)
|
Chris@4
|
193
|
Chris@4
|
194 for api in hostApis:
|
Chris@4
|
195 if api in hostApiHeaders:
|
Chris@4
|
196 env.Install(os.path.join(includeDir, "portaudio"),
|
Chris@4
|
197 File(hostApiHeaders[api], "include"))
|