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",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "Build Hot Reload",
|
||||
"name": "Run Hot Reload (Linux / Mac)",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"program": "${workspaceFolder}/game_hot_reload.bin",
|
||||
"program": "${workspaceFolder}/build/hotreload/game.bin",
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
|
@ -2,8 +2,8 @@ package builder
|
||||
|
||||
import "core:flags"
|
||||
import "core:fmt"
|
||||
import "core:log"
|
||||
import "core:io"
|
||||
import "core:log"
|
||||
import os "core:os/os2"
|
||||
import "core:path/filepath"
|
||||
import "core:slice"
|
||||
@ -30,10 +30,19 @@ temp_concat :: proc(strs: ..[]string) -> []string {
|
||||
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")
|
||||
force := opts.force
|
||||
shared := opts.variant == .Hot_Reload
|
||||
|
||||
out_libs := make([dynamic]string, 0, 3, context.temp_allocator)
|
||||
|
||||
// Raylib
|
||||
{
|
||||
cwd := "./libs/raylib"
|
||||
@ -56,6 +65,10 @@ build_deps :: proc(opts: Options) {
|
||||
},
|
||||
cwd,
|
||||
)
|
||||
|
||||
if shared {
|
||||
append(&out_libs, "./libs/raylib/zig-out-shared/lib/libraylib.so")
|
||||
}
|
||||
}
|
||||
|
||||
// Physfs
|
||||
@ -84,6 +97,10 @@ build_deps :: proc(opts: Options) {
|
||||
run_cmd(build_cmd, cwd)
|
||||
}
|
||||
}
|
||||
|
||||
if shared {
|
||||
append(&out_libs, "./libs/physfs/build/libphysfs.so.1")
|
||||
}
|
||||
}
|
||||
|
||||
// Tracy
|
||||
@ -135,7 +152,13 @@ build_deps :: proc(opts: Options) {
|
||||
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 {
|
||||
@ -176,6 +199,14 @@ setup_emsdk_env :: proc() {
|
||||
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() {
|
||||
context.logger = log.create_console_logger()
|
||||
opts := Options {
|
||||
@ -195,12 +226,11 @@ main :: proc() {
|
||||
debug_flag: []string = opts.debug ? {"-debug"} : {}
|
||||
optimize_flag: []string = opts.optimize ? {"-o:speed"} : {}
|
||||
|
||||
build_deps(opts)
|
||||
shared_dep_paths := build_deps(opts)
|
||||
|
||||
switch opts.variant {
|
||||
case .Hot_Reload:
|
||||
remove_all("./build/hotreload")
|
||||
mkdir_all("./build/hotreload")
|
||||
setup_bin_dir("./build/hotreload", shared_dep_paths)
|
||||
|
||||
is_main_built := os.is_file("./build/hotreload/game.bin")
|
||||
if !is_main_built || opts.force {
|
||||
@ -236,19 +266,24 @@ main :: proc() {
|
||||
COMMON_FLAGS,
|
||||
)
|
||||
build_game_lib :: proc(build_cmd: []string) {
|
||||
run_cmd(
|
||||
build_cmd,
|
||||
"",
|
||||
)
|
||||
run_cmd(build_cmd, "")
|
||||
rename("./build/hotreload/game_tmp.so", "./build/hotreload/game.so")
|
||||
}
|
||||
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.user_ptr = &build_game_cmd
|
||||
thread_ctx.user_ptr = &watcher_ctx
|
||||
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)
|
||||
|
||||
buf: [1024]u8
|
||||
@ -258,7 +293,7 @@ main :: proc() {
|
||||
for cmd in buf[0:n] {
|
||||
switch cmd {
|
||||
case 'r', 'R':
|
||||
build_game_lib(build_game_cmd)
|
||||
build_game_lib(watcher_ctx.build_game_cmd)
|
||||
case:
|
||||
}
|
||||
}
|
||||
@ -272,11 +307,10 @@ main :: proc() {
|
||||
}, thread_ctx)
|
||||
|
||||
run_cmd({"./build/hotreload/game.bin"}, "")
|
||||
thread.join(thrd)
|
||||
}
|
||||
case .Desktop:
|
||||
remove_all("./build/desktop")
|
||||
mkdir_all("./build/desktop")
|
||||
setup_bin_dir("./build/desktop", shared_dep_paths)
|
||||
|
||||
cmd := slice.concatenate(
|
||||
[][]string {
|
||||
[]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) {
|
||||
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(
|
||||
@ -199,3 +202,18 @@ set_env :: proc(env, val: string) {
|
||||
log.infof("set_env(%s, %s)", 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)
|
||||
switch ctx.bytes[ctx.it] {
|
||||
case 'v':
|
||||
log.debugf("v line: %v", ctx.line)
|
||||
// vertex
|
||||
advance(&ctx) or_break
|
||||
log.debugf("after advance %v", ctx.bytes[ctx.it])
|
||||
|
||||
vertex: rl.Vector3
|
||||
|
||||
@ -453,10 +451,14 @@ get_convex :: proc(assetman: ^Asset_Manager, path: cstring) -> (result: Loaded_C
|
||||
s := string(ctx.bytes[ctx.it:])
|
||||
coord_val, nr, ok := strconv.parse_f32_prefix(s)
|
||||
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
|
||||
}
|
||||
log.debugf("parsed float %v %v from %s", coord_idx, coord_val, ctx.bytes[ctx.it:][:nr])
|
||||
advance(&ctx, nr) or_break
|
||||
|
||||
vertex[coord_idx] = coord_val
|
||||
|
18
game/fs.odin
18
game/fs.odin
@ -3,6 +3,7 @@ package game
|
||||
import "base:runtime"
|
||||
import "core:c"
|
||||
import "core:log"
|
||||
import "core:path/filepath"
|
||||
import "core:strings"
|
||||
import "libs:physfs"
|
||||
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.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() {
|
||||
|
@ -1265,9 +1265,7 @@ game_update :: proc() -> bool {
|
||||
|
||||
when ODIN_OS != .JS {
|
||||
// Never run this proc in browser. It contains a 16 ms sleep on web!
|
||||
if rl.WindowShouldClose() {
|
||||
return true
|
||||
}
|
||||
return !rl.WindowShouldClose()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -23,11 +23,13 @@ when ODIN_OS == .Windows {
|
||||
TRACY_ENABLE :: #config(TRACY_ENABLE, false)
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
@ -60,29 +62,18 @@ load_game_api :: proc(api_version: int) -> (api: Game_API, ok: bool) {
|
||||
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.
|
||||
game_dll_name := filepath.join(
|
||||
{
|
||||
cwd,
|
||||
fmt.tprintf(
|
||||
"{0}game_{1}" + DLL_EXT,
|
||||
"./" when ODIN_OS != .Windows else "",
|
||||
api_version,
|
||||
),
|
||||
},
|
||||
context.temp_allocator,
|
||||
)
|
||||
copy_dll(game_dll_name) or_return
|
||||
game_dll_name := fmt.tprintf("game_{0}" + DLL_EXT, api_version)
|
||||
bin_dir := filepath.dir(os.args[0], context.temp_allocator)
|
||||
|
||||
copy_dll(bin_dir, game_dll_name) or_return
|
||||
|
||||
game_dll_path := filepath.join({bin_dir, game_dll_name}, context.temp_allocator)
|
||||
|
||||
// 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
|
||||
// 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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -117,6 +115,10 @@ main :: proc() {
|
||||
secure = true,
|
||||
)
|
||||
}
|
||||
|
||||
bin_dir := filepath.dir(os.args[0])
|
||||
defer delete(bin_dir)
|
||||
|
||||
default_allocator := context.allocator
|
||||
tracking_allocator: mem.Tracking_Allocator
|
||||
mem.tracking_allocator_init(&tracking_allocator, default_allocator)
|
||||
@ -154,7 +156,9 @@ main :: proc() {
|
||||
force_reload := game_api.force_reload()
|
||||
force_restart := game_api.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 {
|
||||
reload = true
|
||||
@ -245,4 +249,3 @@ NvOptimusEnablement: u32 = 1
|
||||
|
||||
@(export)
|
||||
AmdPowerXpressRequestHighPerformance: i32 = 1
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user