Clone of Bael'Zharon's Respite @ https://github.com/boardwalk/bzr

make_ninja_build.py 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. #!/usr/bin/env python
  2. import argparse
  3. import ninja_syntax
  4. import os
  5. import re
  6. import subprocess
  7. import sys
  8. os.chdir(os.path.dirname(os.path.realpath(__file__)))
  9. def uniq(inp):
  10. out = []
  11. first = True
  12. prev = None
  13. for val in inp:
  14. if first or val != prev:
  15. out.append(val)
  16. first = False
  17. prev = val
  18. return out
  19. # super fantastically ghetto dependency discovery
  20. def includes(path):
  21. def collect(path, result):
  22. if not os.path.exists(path):
  23. return
  24. with open(path) as f:
  25. for ln in f:
  26. m = re.match(r'\s*#include "(.+)"', ln)
  27. if m:
  28. base_depend_path = m.group(1)
  29. # our include directives use forward slashes, use backslash on windows
  30. if sys.platform == 'win32':
  31. base_depend_path = base_depend_path.replace('/', '\\')
  32. depend_path = os.path.join('include', base_depend_path)
  33. # if it doesn't exist in include, try source instead
  34. if not os.path.exists(depend_path):
  35. depend_path = os.path.join('source', base_depend_path);
  36. # if it doesn't exist in either of those, try build instead
  37. if not os.path.exists(depend_path):
  38. depend_path = os.path.join('build', base_depend_path)
  39. result.append(depend_path)
  40. collect(depend_path, result)
  41. result = []
  42. collect(path, result)
  43. return uniq(sorted(result))
  44. def execute(*args):
  45. return subprocess.check_output(args).decode('utf-8').strip()
  46. def splitall(path):
  47. result = []
  48. while path:
  49. head, tail = os.path.split(path)
  50. result.insert(0, tail)
  51. path = head
  52. return result
  53. def change_top_dir(path, new_top_dir):
  54. parts = splitall(path)
  55. return os.path.join(new_top_dir, *parts[1:])
  56. def main():
  57. parser = argparse.ArgumentParser()
  58. parser.add_argument('--release', action='store_true', default=False)
  59. parser.add_argument('--headless', action='store_true', default=False)
  60. parser.add_argument('--oculusvr', action='store_true', default=False)
  61. args = parser.parse_args()
  62. with open('build.ninja', 'w') as buildfile:
  63. n = ninja_syntax.Writer(buildfile)
  64. n.variable('builddir', 'build')
  65. if sys.platform == 'win32':
  66. cppflags = '/nologo /EHsc /Iinclude /Ibuild /D_CRT_SECURE_NO_WARNINGS /DNOMINMAX'
  67. cxxflags = '/FIbasic.h /W4 /WX'
  68. cflags = ''
  69. linkflags = '/nologo ws2_32.lib'
  70. sdl_dir = os.path.expanduser(r'~\Documents\SDL2-2.0.3')
  71. cppflags += r' /MD /I{}\include'.format(sdl_dir)
  72. linkflags += r' /libpath:{0}\VisualC\SDL\x64\Release /libpath:{0}\VisualC\SDLmain\x64\Release SDL2.lib SDL2main.lib'.format(sdl_dir)
  73. jansson_dir = os.path.expanduser(r'~\Documents\jansson-2.7\VisualStudioSolution')
  74. cppflags += r' /I{}\include'.format(jansson_dir)
  75. linkflags += r' /libpath:{}\x64\Release jansson.lib advapi32.lib'.format(jansson_dir)
  76. glm_dir = os.path.expanduser(r'~\Documents\glm')
  77. cppflags += r' /I{}'.format(glm_dir)
  78. if not args.headless:
  79. glew_dir = os.path.expanduser(r'~\Documents\glew-1.12.0')
  80. cppflags += r' /I{}\include'.format(glew_dir)
  81. linkflags += r' /libpath:{}\lib\Release\x64 OpenGL32.lib glew32.lib'.format(glew_dir)
  82. if args.oculusvr:
  83. ovr_dir = os.path.expanduser(r'~\Documents\OculusSDK\LibOVR')
  84. cppflags += r' /I{}\Src /DOVR_OS_WIN32 /DOCULUSVR'.format(ovr_dir)
  85. # there are VS2010 and 2013 directories too
  86. # i'm only testing this support with VS 2013 right now
  87. # attn! libovr requires atls.lib, which is not provided by VS Express
  88. # the version provided in the WDK does *not* work, you need the full version of VS
  89. linkflags += r' /libpath:{}\Lib\x64\VS2013 libovr64.lib winmm.lib gdi32.lib shell32.lib'.format(ovr_dir)
  90. if args.release:
  91. cppflags += ' /O2 /GL /DNDEBUG'
  92. linkflags += ' /LTCG'
  93. else:
  94. cppflags += r' /Zi /Fdoutput\bzr.pdb /FS'
  95. linkflags += ' /DEBUG'
  96. if args.release and not args.headless:
  97. linkflags += ' /subsystem:WINDOWS'
  98. else:
  99. linkflags += ' /subsystem:CONSOLE'
  100. if args.headless:
  101. cppflags += ' /DHEADLESS'
  102. n.variable('cppflags', cppflags)
  103. n.variable('cxxflags', cxxflags)
  104. n.variable('cflags', cflags)
  105. n.variable('linkflags', linkflags)
  106. n.variable('appext', '.exe')
  107. n.rule('c', 'cl $cppflags $cflags /c $in /Fo$out')
  108. n.rule('cxx', 'cl $cppflags $cxxflags /c $in /Fo$out')
  109. n.rule('link', 'link $linkflags $in /out:$out')
  110. n.rule('header', 'python make_include_file.py $in $out')
  111. n.rule('copy', 'cmd /c copy $in $out')
  112. n.build(r'output\SDL2.dll', 'copy', r'{}\VisualC\SDL\x64\Release\SDL2.dll'.format(sdl_dir))
  113. n.default(r'output\SDL2.dll')
  114. if not args.headless:
  115. n.build(r'output\glew32.dll', 'copy', r'{}\bin\Release\x64\glew32.dll'.format(glew_dir))
  116. n.default(r'output\glew32.dll')
  117. else:
  118. # applied to 'c' rule only
  119. cflags = ''
  120. # applied to 'cxx' rule only
  121. cxxflags = ''
  122. # applied to everything, including link
  123. cppflags = ''
  124. ldflags = ''
  125. linkextra = ''
  126. cxxflags += ' -std=c++11'
  127. cxxflags += ' -include ' + os.path.join('include', 'basic.h')
  128. cppflags += ' -Iinclude -Ibuild'
  129. cppflags += ' -Wall -Wextra -Wformat=2 -Wno-format-nonliteral -Wshadow'
  130. cppflags += ' -Wpointer-arith -Wcast-qual -Wno-missing-braces'
  131. cppflags += ' -Werror -pedantic-errors'
  132. cppflags += ' -Wstrict-aliasing=1'
  133. cppflags += ' -Wno-unused-parameter' # annoying error when stubbing things out
  134. cppflags += ' -Wno-shadow'
  135. cppflags += ' ' + execute('sdl2-config', '--cflags')
  136. ldflags += ' ' + execute('sdl2-config', '--libs')
  137. cppflags += ' ' + execute('pkg-config', '--cflags', 'jansson')
  138. ldflags += ' ' + execute('pkg-config', '--libs', 'jansson')
  139. if not args.headless:
  140. if sys.platform == 'darwin':
  141. ldflags += ' -framework OpenGL'
  142. else:
  143. ldflags += ' -lGL'
  144. if args.oculusvr:
  145. ovr_dir = os.path.expanduser('~/Documents/OculusSDK/LibOVR')
  146. cppflags += ' -I{}/Src -DOVR_OS_MAC -DOCULUSVR'.format(ovr_dir)
  147. ldflags += ' -L{}/Lib/Mac/Release -lovr -framework CoreFoundation -framework CoreGraphics -framework IOKit'.format(ovr_dir)
  148. if args.release:
  149. cppflags += ' -O2 -flto -DNDEBUG'
  150. if sys.platform == 'darwin':
  151. linkextra = ' && strip $out'
  152. else:
  153. linkextra = ' && strip -s $out'
  154. else:
  155. cppflags += ' -g'
  156. if args.headless:
  157. cxxflags += ' -DHEADLESS'
  158. n.variable('cppflags', cppflags)
  159. n.variable('cflags', cflags)
  160. n.variable('cxxflags', cxxflags)
  161. n.variable('ldflags', ldflags)
  162. n.variable('appext', '')
  163. n.rule('c', 'gcc-4.9 $cppflags $cflags -c $in -o $out')
  164. n.rule('cxx', 'g++-4.9 $cppflags $cxxflags -c $in -o $out')
  165. n.rule('link', 'g++-4.9 $cppflags $in $ldflags -o $out' + linkextra)
  166. n.rule('header', './make_include_file.py $in $out')
  167. link_inputs = []
  168. for dirpath, dirnames, filenames in os.walk('source'):
  169. if args.headless and splitall(dirpath)[0:2] == ['source', 'graphics']:
  170. continue
  171. for filename in filenames:
  172. name, ext = os.path.splitext(filename)
  173. in_file = os.path.join(dirpath, filename)
  174. if ext == '.glsl':
  175. buildrule = 'header'
  176. newext = '.h'
  177. implicit = includes(in_file)
  178. elif ext == '.cpp':
  179. buildrule = 'cxx'
  180. newext = '.o'
  181. # all c++ is dependent on basic.h
  182. implicit = includes(in_file)
  183. implicit.append(os.path.join('include', 'basic.h'))
  184. elif ext == '.c':
  185. buildrule = 'c'
  186. newext = '.o'
  187. implicit = includes(in_file)
  188. else:
  189. continue
  190. out_file = os.path.join(change_top_dir(dirpath, 'build'), name + newext)
  191. n.build(out_file, buildrule, in_file, implicit)
  192. if ext == '.cpp' or ext == '.c':
  193. link_inputs.append(out_file)
  194. n.build(os.path.join('output', 'bzr$appext'), 'link', link_inputs)
  195. n.default(os.path.join('output', 'bzr$appext'))
  196. if __name__ == '__main__':
  197. main()