More progress on builder
This commit is contained in:
parent
875ff96f4a
commit
8b8ab8c6bc
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@ -50,11 +50,10 @@
|
|||||||
{
|
{
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"preLaunchTask": "Build Hot Reload",
|
|
||||||
"name": "Run Hot Reload (Linux / Mac)",
|
"name": "Run Hot Reload (Linux / Mac)",
|
||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"program": "${workspaceFolder}/game_hot_reload.bin",
|
"program": "${workspaceFolder}/build/hotreload/game.bin",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
|
@ -2,8 +2,8 @@ package builder
|
|||||||
|
|
||||||
import "core:flags"
|
import "core:flags"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:log"
|
|
||||||
import "core:io"
|
import "core:io"
|
||||||
|
import "core:log"
|
||||||
import os "core:os/os2"
|
import os "core:os/os2"
|
||||||
import "core:path/filepath"
|
import "core:path/filepath"
|
||||||
import "core:slice"
|
import "core:slice"
|
||||||
@ -30,10 +30,19 @@ temp_concat :: proc(strs: ..[]string) -> []string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
build_deps :: proc(opts: Options) {
|
temp_path_join :: proc(paths: ..string) -> string {
|
||||||
|
result, _ := filepath.join(paths, context.temp_allocator)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a list of shared dependencies that have to be copied to out dir
|
||||||
|
build_deps :: proc(opts: Options) -> []string {
|
||||||
log.infof("build_deps")
|
log.infof("build_deps")
|
||||||
force := opts.force
|
force := opts.force
|
||||||
shared := opts.variant == .Hot_Reload
|
shared := opts.variant == .Hot_Reload
|
||||||
|
|
||||||
|
out_libs := make([dynamic]string, 0, 3, context.temp_allocator)
|
||||||
|
|
||||||
// Raylib
|
// Raylib
|
||||||
{
|
{
|
||||||
cwd := "./libs/raylib"
|
cwd := "./libs/raylib"
|
||||||
@ -56,6 +65,10 @@ build_deps :: proc(opts: Options) {
|
|||||||
},
|
},
|
||||||
cwd,
|
cwd,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if shared {
|
||||||
|
append(&out_libs, "./libs/raylib/zig-out-shared/lib/libraylib.so")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Physfs
|
// Physfs
|
||||||
@ -84,6 +97,10 @@ build_deps :: proc(opts: Options) {
|
|||||||
run_cmd(build_cmd, cwd)
|
run_cmd(build_cmd, cwd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if shared {
|
||||||
|
append(&out_libs, "./libs/physfs/build/libphysfs.so.1")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tracy
|
// Tracy
|
||||||
@ -135,9 +152,15 @@ build_deps :: proc(opts: Options) {
|
|||||||
run_cmd({"zig", "ar", "rc", TRACY_NAME_STATIC, "tracy.o"}, cwd)
|
run_cmd({"zig", "ar", "rc", TRACY_NAME_STATIC, "tracy.o"}, cwd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if shared {
|
||||||
|
append(&out_libs, "./libs/tracy/tracy.so")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return out_libs[:]
|
||||||
|
}
|
||||||
|
|
||||||
COMMON_FLAGS :: []string {
|
COMMON_FLAGS :: []string {
|
||||||
"-collection:libs=./libs",
|
"-collection:libs=./libs",
|
||||||
"-collection:common=./common",
|
"-collection:common=./common",
|
||||||
@ -176,6 +199,14 @@ setup_emsdk_env :: proc() {
|
|||||||
set_env("EMSDK", absolute_path("./libs/emsdk"))
|
set_env("EMSDK", absolute_path("./libs/emsdk"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_bin_dir :: proc(path: string, files_to_copy: []string) {
|
||||||
|
mkdir_all(path)
|
||||||
|
|
||||||
|
for file in files_to_copy {
|
||||||
|
copy_file(file, temp_path_join(path, filepath.base(file)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
context.logger = log.create_console_logger()
|
context.logger = log.create_console_logger()
|
||||||
opts := Options {
|
opts := Options {
|
||||||
@ -195,12 +226,11 @@ main :: proc() {
|
|||||||
debug_flag: []string = opts.debug ? {"-debug"} : {}
|
debug_flag: []string = opts.debug ? {"-debug"} : {}
|
||||||
optimize_flag: []string = opts.optimize ? {"-o:speed"} : {}
|
optimize_flag: []string = opts.optimize ? {"-o:speed"} : {}
|
||||||
|
|
||||||
build_deps(opts)
|
shared_dep_paths := build_deps(opts)
|
||||||
|
|
||||||
switch opts.variant {
|
switch opts.variant {
|
||||||
case .Hot_Reload:
|
case .Hot_Reload:
|
||||||
remove_all("./build/hotreload")
|
setup_bin_dir("./build/hotreload", shared_dep_paths)
|
||||||
mkdir_all("./build/hotreload")
|
|
||||||
|
|
||||||
is_main_built := os.is_file("./build/hotreload/game.bin")
|
is_main_built := os.is_file("./build/hotreload/game.bin")
|
||||||
if !is_main_built || opts.force {
|
if !is_main_built || opts.force {
|
||||||
@ -236,19 +266,24 @@ main :: proc() {
|
|||||||
COMMON_FLAGS,
|
COMMON_FLAGS,
|
||||||
)
|
)
|
||||||
build_game_lib :: proc(build_cmd: []string) {
|
build_game_lib :: proc(build_cmd: []string) {
|
||||||
run_cmd(
|
run_cmd(build_cmd, "")
|
||||||
build_cmd,
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
rename("./build/hotreload/game_tmp.so", "./build/hotreload/game.so")
|
rename("./build/hotreload/game_tmp.so", "./build/hotreload/game.so")
|
||||||
}
|
}
|
||||||
build_game_lib(build_game_cmd)
|
build_game_lib(build_game_cmd)
|
||||||
|
|
||||||
if opts.run {
|
if opts.run && !process_exists("game.bin") {
|
||||||
|
Watcher_Context :: struct {
|
||||||
|
run: bool,
|
||||||
|
build_game_cmd: []string,
|
||||||
|
}
|
||||||
|
watcher_ctx := Watcher_Context {
|
||||||
|
run = true,
|
||||||
|
build_game_cmd = build_game_cmd,
|
||||||
|
}
|
||||||
thread_ctx := context
|
thread_ctx := context
|
||||||
thread_ctx.user_ptr = &build_game_cmd
|
thread_ctx.user_ptr = &watcher_ctx
|
||||||
thrd := thread.create_and_start(proc() {
|
thrd := thread.create_and_start(proc() {
|
||||||
build_game_cmd := (cast(^[]string)context.user_ptr)^
|
watcher_ctx := (cast(^Watcher_Context)context.user_ptr)
|
||||||
input := os.to_reader(os.stdin)
|
input := os.to_reader(os.stdin)
|
||||||
|
|
||||||
buf: [1024]u8
|
buf: [1024]u8
|
||||||
@ -258,7 +293,7 @@ main :: proc() {
|
|||||||
for cmd in buf[0:n] {
|
for cmd in buf[0:n] {
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case 'r', 'R':
|
case 'r', 'R':
|
||||||
build_game_lib(build_game_cmd)
|
build_game_lib(watcher_ctx.build_game_cmd)
|
||||||
case:
|
case:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -272,11 +307,10 @@ main :: proc() {
|
|||||||
}, thread_ctx)
|
}, thread_ctx)
|
||||||
|
|
||||||
run_cmd({"./build/hotreload/game.bin"}, "")
|
run_cmd({"./build/hotreload/game.bin"}, "")
|
||||||
thread.join(thrd)
|
|
||||||
}
|
}
|
||||||
case .Desktop:
|
case .Desktop:
|
||||||
remove_all("./build/desktop")
|
setup_bin_dir("./build/desktop", shared_dep_paths)
|
||||||
mkdir_all("./build/desktop")
|
|
||||||
cmd := slice.concatenate(
|
cmd := slice.concatenate(
|
||||||
[][]string {
|
[][]string {
|
||||||
[]string{"odin", "build", "main_release", "-out:./build/desktop/game.exe"},
|
[]string{"odin", "build", "main_release", "-out:./build/desktop/game.exe"},
|
||||||
@ -343,4 +377,3 @@ main :: proc() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +180,10 @@ rename :: proc(src, dst: string, expr := #caller_expression, loc := #caller_loca
|
|||||||
|
|
||||||
mkdir_all :: proc(path: string, expr := #caller_expression, loc := #caller_location) {
|
mkdir_all :: proc(path: string, expr := #caller_expression, loc := #caller_location) {
|
||||||
log.infof("mkdir -p %s", path)
|
log.infof("mkdir -p %s", path)
|
||||||
handle_error(os.mkdir_all(path), "", expr, loc)
|
err := os.mkdir_all(path)
|
||||||
|
if err != .Exist {
|
||||||
|
handle_error(err, "", expr, loc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
absolute_path :: proc(
|
absolute_path :: proc(
|
||||||
@ -199,3 +202,18 @@ set_env :: proc(env, val: string) {
|
|||||||
log.infof("set_env(%s, %s)", env, val)
|
log.infof("set_env(%s, %s)", env, val)
|
||||||
handle_error(os.set_env(env, val))
|
handle_error(os.set_env(env, val))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process_exists :: proc(name: string) -> bool {
|
||||||
|
pids := handle_error1(os.process_list(context.temp_allocator))
|
||||||
|
|
||||||
|
for pid in pids {
|
||||||
|
pinfo, err := os.process_info_by_pid(pid, {.Executable_Path}, context.temp_allocator)
|
||||||
|
if err == nil {
|
||||||
|
if filepath.base(pinfo.executable_path) == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -440,10 +440,8 @@ get_convex :: proc(assetman: ^Asset_Manager, path: cstring) -> (result: Loaded_C
|
|||||||
skip_whitespase(&ctx)
|
skip_whitespase(&ctx)
|
||||||
switch ctx.bytes[ctx.it] {
|
switch ctx.bytes[ctx.it] {
|
||||||
case 'v':
|
case 'v':
|
||||||
log.debugf("v line: %v", ctx.line)
|
|
||||||
// vertex
|
// vertex
|
||||||
advance(&ctx) or_break
|
advance(&ctx) or_break
|
||||||
log.debugf("after advance %v", ctx.bytes[ctx.it])
|
|
||||||
|
|
||||||
vertex: rl.Vector3
|
vertex: rl.Vector3
|
||||||
|
|
||||||
@ -453,10 +451,14 @@ get_convex :: proc(assetman: ^Asset_Manager, path: cstring) -> (result: Loaded_C
|
|||||||
s := string(ctx.bytes[ctx.it:])
|
s := string(ctx.bytes[ctx.it:])
|
||||||
coord_val, nr, ok := strconv.parse_f32_prefix(s)
|
coord_val, nr, ok := strconv.parse_f32_prefix(s)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.errorf("failed to parse float %v %s at line %d", coord_idx, ctx.bytes[ctx.it:][:12], ctx.line)
|
log.errorf(
|
||||||
|
"failed to parse float %v %s at line %d",
|
||||||
|
coord_idx,
|
||||||
|
ctx.bytes[ctx.it:][:12],
|
||||||
|
ctx.line,
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.debugf("parsed float %v %v from %s", coord_idx, coord_val, ctx.bytes[ctx.it:][:nr])
|
|
||||||
advance(&ctx, nr) or_break
|
advance(&ctx, nr) or_break
|
||||||
|
|
||||||
vertex[coord_idx] = coord_val
|
vertex[coord_idx] = coord_val
|
||||||
|
18
game/fs.odin
18
game/fs.odin
@ -3,6 +3,7 @@ package game
|
|||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
import "core:c"
|
import "core:c"
|
||||||
import "core:log"
|
import "core:log"
|
||||||
|
import "core:path/filepath"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "libs:physfs"
|
import "libs:physfs"
|
||||||
import rl "libs:raylib"
|
import rl "libs:raylib"
|
||||||
@ -15,6 +16,23 @@ init_physfs :: proc(args: []string) {
|
|||||||
|
|
||||||
physfs.init(strings.clone_to_cstring(args[0], context.temp_allocator))
|
physfs.init(strings.clone_to_cstring(args[0], context.temp_allocator))
|
||||||
physfs.setSaneConfig("serega", "gutter-runner", "zip", 0, 1)
|
physfs.setSaneConfig("serega", "gutter-runner", "zip", 0, 1)
|
||||||
|
|
||||||
|
// For non web builds, binary will live 2 subdirs below main content dir, so add it to search path
|
||||||
|
if args[0] != "." {
|
||||||
|
base_dir := filepath.dir(
|
||||||
|
filepath.dir(filepath.dir(args[0], context.temp_allocator), context.temp_allocator),
|
||||||
|
context.temp_allocator,
|
||||||
|
)
|
||||||
|
abs_base_dir, ok := filepath.abs(base_dir, context.temp_allocator)
|
||||||
|
assert(ok)
|
||||||
|
err := physfs.mount(strings.clone_to_cstring(abs_base_dir, context.temp_allocator), "/", 1)
|
||||||
|
|
||||||
|
if err == 0 {
|
||||||
|
log.panicf("physfs: failed to set base dir {0}", physfs.getLastError())
|
||||||
|
}
|
||||||
|
|
||||||
|
log.infof("physfs: added {0} to search path", abs_base_dir)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init_physifs_raylib_callbacks :: proc() {
|
init_physifs_raylib_callbacks :: proc() {
|
||||||
|
@ -1265,9 +1265,7 @@ game_update :: proc() -> bool {
|
|||||||
|
|
||||||
when ODIN_OS != .JS {
|
when ODIN_OS != .JS {
|
||||||
// Never run this proc in browser. It contains a 16 ms sleep on web!
|
// Never run this proc in browser. It contains a 16 ms sleep on web!
|
||||||
if rl.WindowShouldClose() {
|
return !rl.WindowShouldClose()
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,13 @@ when ODIN_OS == .Windows {
|
|||||||
TRACY_ENABLE :: #config(TRACY_ENABLE, false)
|
TRACY_ENABLE :: #config(TRACY_ENABLE, false)
|
||||||
|
|
||||||
// We copy the DLL because using it directly would lock it, which would prevent
|
// We copy the DLL because using it directly would lock it, which would prevent
|
||||||
// the compiler from writing to it.
|
// the compiler from writing to it (on windows).
|
||||||
copy_dll :: proc(bin_dir, to: string) -> bool {
|
copy_dll :: proc(bin_dir, to: string) -> bool {
|
||||||
err := os2.copy_file(filepath.join({bin_dir, to}, context.temp_allocator), filepath.join({bin_dir, "game" + DLL_EXT}, context.temp_allocator), )
|
src := filepath.join({bin_dir, "game" + DLL_EXT}, context.temp_allocator)
|
||||||
|
dst := filepath.join({bin_dir, to}, context.temp_allocator)
|
||||||
|
err := os2.copy_file(dst, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.printfln("Failed to copy game" + DLL_EXT + " to {0}", to)
|
fmt.printfln("Error {0}: Failed to copy {1} to {2}", err, src, dst)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,29 +62,18 @@ load_game_api :: proc(api_version: int) -> (api: Game_API, ok: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cwd, err := os2.getwd(context.temp_allocator)
|
|
||||||
if err != nil {
|
|
||||||
log.panicf("getcwd: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: this needs to be a relative path for Linux to work.
|
// NOTE: this needs to be a relative path for Linux to work.
|
||||||
game_dll_name := filepath.join(
|
game_dll_name := fmt.tprintf("game_{0}" + DLL_EXT, api_version)
|
||||||
{
|
bin_dir := filepath.dir(os.args[0], context.temp_allocator)
|
||||||
cwd,
|
|
||||||
fmt.tprintf(
|
copy_dll(bin_dir, game_dll_name) or_return
|
||||||
"{0}game_{1}" + DLL_EXT,
|
|
||||||
"./" when ODIN_OS != .Windows else "",
|
game_dll_path := filepath.join({bin_dir, game_dll_name}, context.temp_allocator)
|
||||||
api_version,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
context.temp_allocator,
|
|
||||||
)
|
|
||||||
copy_dll(game_dll_name) or_return
|
|
||||||
|
|
||||||
// This proc matches the names of the fields in Game_API to symbols in the
|
// This proc matches the names of the fields in Game_API to symbols in the
|
||||||
// game DLL. It actually looks for symbols starting with `game_`, which is
|
// game DLL. It actually looks for symbols starting with `game_`, which is
|
||||||
// why the argument `"game_"` is there.
|
// why the argument `"game_"` is there.
|
||||||
_, ok = dynlib.initialize_symbols(&api, game_dll_name, "game_", "lib")
|
_, ok = dynlib.initialize_symbols(&api, game_dll_path, "game_", "lib")
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.printfln("Failed initializing symbols: {0}", dynlib.last_error())
|
fmt.printfln("Failed initializing symbols: {0}", dynlib.last_error())
|
||||||
}
|
}
|
||||||
@ -101,7 +92,14 @@ unload_game_api :: proc(api: ^Game_API) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if os.remove(fmt.tprintf("game_{0}" + DLL_EXT, api.api_version)) != nil {
|
bin_dir := filepath.dir(os.args[0], context.temp_allocator)
|
||||||
|
|
||||||
|
game_dll_path := filepath.join(
|
||||||
|
{bin_dir, fmt.tprintf("game_{0}" + DLL_EXT, api.api_version)},
|
||||||
|
context.temp_allocator,
|
||||||
|
)
|
||||||
|
|
||||||
|
if os2.remove(game_dll_path) != nil {
|
||||||
fmt.printfln("Failed to remove game_{0}" + DLL_EXT + " copy", api.api_version)
|
fmt.printfln("Failed to remove game_{0}" + DLL_EXT + " copy", api.api_version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,6 +115,10 @@ main :: proc() {
|
|||||||
secure = true,
|
secure = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bin_dir := filepath.dir(os.args[0])
|
||||||
|
defer delete(bin_dir)
|
||||||
|
|
||||||
default_allocator := context.allocator
|
default_allocator := context.allocator
|
||||||
tracking_allocator: mem.Tracking_Allocator
|
tracking_allocator: mem.Tracking_Allocator
|
||||||
mem.tracking_allocator_init(&tracking_allocator, default_allocator)
|
mem.tracking_allocator_init(&tracking_allocator, default_allocator)
|
||||||
@ -154,7 +156,9 @@ main :: proc() {
|
|||||||
force_reload := game_api.force_reload()
|
force_reload := game_api.force_reload()
|
||||||
force_restart := game_api.force_restart()
|
force_restart := game_api.force_restart()
|
||||||
reload := force_reload || force_restart
|
reload := force_reload || force_restart
|
||||||
game_dll_mod, game_dll_mod_err := os.last_write_time_by_name("game" + DLL_EXT)
|
game_dll_mod, game_dll_mod_err := os.last_write_time_by_name(
|
||||||
|
filepath.join({bin_dir, "game" + DLL_EXT}, context.temp_allocator),
|
||||||
|
)
|
||||||
|
|
||||||
if game_dll_mod_err == os.ERROR_NONE && game_api.modification_time != game_dll_mod {
|
if game_dll_mod_err == os.ERROR_NONE && game_api.modification_time != game_dll_mod {
|
||||||
reload = true
|
reload = true
|
||||||
@ -245,4 +249,3 @@ NvOptimusEnablement: u32 = 1
|
|||||||
|
|
||||||
@(export)
|
@(export)
|
||||||
AmdPowerXpressRequestHighPerformance: i32 = 1
|
AmdPowerXpressRequestHighPerformance: i32 = 1
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user