You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
6.9KB

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