| 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")) |