build_web.odin 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // This program builds a Karl2D game as a web version.
  2. //
  3. // Usage:
  4. // odin run build_web -- directory_name
  5. //
  6. // For example:
  7. // odin run build_web -- examples/minimal_web
  8. //
  9. // This program copies the `odin.js` from `<odin>/core/sys/wasm/js/odin.js` to the `bin/web` folder.
  10. // It also copies an `index.html` file to the `bin/web` folder. It also copies a `web_entry.odin`
  11. // file into the `build/web` folder. That's the file which is actually built. It contains some
  12. // wrapper code that calls into your game. The wrapper, and your game, is built using the
  13. // `js_wasm32` target. The resulting `main.wasm` file is also put in the `build/web` folder.
  14. package karl2d_build_web_tool
  15. import "core:fmt"
  16. import "core:path/filepath"
  17. import os "core:os/os2"
  18. import "core:strings"
  19. main :: proc() {
  20. print_usage: bool
  21. if len(os.args) < 2 {
  22. print_usage = true
  23. }
  24. debug := false
  25. opt_string: string
  26. dir: string
  27. for a in os.args {
  28. if a == "-debug" {
  29. debug = true
  30. } else if a == "-help" {
  31. print_usage = true
  32. } else if a == "-o:speed" {
  33. opt_string = a
  34. } else if a == "-o:size" {
  35. opt_string = a
  36. } else if strings.has_prefix(a, "-") {
  37. print_usage = true
  38. } else {
  39. dir = a
  40. }
  41. }
  42. if dir == "" {
  43. print_usage = true
  44. }
  45. if print_usage {
  46. fmt.eprintfln("Usage: 'odin run build_web -- directory_name [-debug] [-o:speed/size]' where `[]` means that it is an optional flag\nExample: 'odin run build_web -- examples/minimal_web'")
  47. return
  48. }
  49. WEB_ENTRY_TEMPLATE :: #load("web_entry_templates/web_entry_template.odin")
  50. WEB_ENTRY_INDEX :: #load("web_entry_templates/index_template.html")
  51. dir_handle, dir_handle_err := os.open(dir)
  52. fmt.ensuref(dir_handle_err == nil, "Failed finding directory %v. Error: %v", dir, dir_handle_err)
  53. dir_stat, dir_stat_err := os.fstat(dir_handle, context.allocator)
  54. fmt.ensuref(dir_stat_err == nil, "Failed checking status of directory %v. Error: %v", dir, dir_stat_err)
  55. fmt.ensuref(dir_stat.type == .Directory, "%v is not a directory!", dir)
  56. dir_name := dir_stat.name
  57. bin_dir := filepath.join({dir, "bin"})
  58. os.make_directory(bin_dir, 0o755)
  59. bin_web_dir := filepath.join({bin_dir, "web"})
  60. os.make_directory(bin_web_dir, 0o755)
  61. build_dir := filepath.join({dir, "build"})
  62. os.make_directory(build_dir, 0o755)
  63. build_web_dir := filepath.join({build_dir, "web"})
  64. os.make_directory(build_web_dir, 0o755)
  65. entry_odin_file_path := filepath.join({build_web_dir, fmt.tprintf("%v_web_entry.odin", dir_name)})
  66. write_entry_odin_err := os.write_entire_file(entry_odin_file_path, WEB_ENTRY_TEMPLATE)
  67. fmt.ensuref(write_entry_odin_err == nil, "Failed writing %v. Error: %v", entry_odin_file_path, write_entry_odin_err)
  68. entry_html_file_path := filepath.join({bin_web_dir, "index.html"})
  69. write_entry_html_err := os.write_entire_file(entry_html_file_path, WEB_ENTRY_INDEX)
  70. fmt.ensuref(write_entry_html_err == nil, "Failed writing %v. Error: %v", entry_html_file_path, write_entry_html_err)
  71. _, odin_root_stdout, _, odin_root_err := os.process_exec({
  72. command = { "odin", "root" },
  73. }, allocator = context.allocator)
  74. ensure(odin_root_err == nil, "Failed fetching 'odin root' (Odin in PATH needed!)")
  75. odin_root := string(odin_root_stdout)
  76. js_runtime_path := filepath.join({odin_root, "core", "sys", "wasm", "js", "odin.js"})
  77. fmt.ensuref(os.exists(js_runtime_path), "File does not exist: %v -- It is the Odin Javascript runtime that this program needs to copy to the web build output folder!", js_runtime_path)
  78. os.copy_file(filepath.join({bin_web_dir, "odin.js"}), js_runtime_path)
  79. wasm_out_path := filepath.join({bin_web_dir, "main.wasm"})
  80. build_command: [dynamic]string
  81. append(&build_command, ..[]string{
  82. "odin",
  83. "build",
  84. build_web_dir,
  85. fmt.tprintf("-out:%v", wasm_out_path),
  86. "-target:js_wasm32",
  87. "-vet",
  88. "-strict-style",
  89. })
  90. if debug {
  91. append(&build_command, "-debug")
  92. }
  93. if opt_string != "" {
  94. append(&build_command, opt_string)
  95. }
  96. _, build_std_out, build_std_err, _ := os.process_exec({ command = build_command[:] }, allocator = context.allocator)
  97. if len(build_std_out) > 0 {
  98. fmt.println(string(build_std_out))
  99. }
  100. if len(build_std_err) > 0 {
  101. fmt.println(string(build_std_err))
  102. }
  103. }