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