aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2024-07-08 23:39:14 +0100
committergingerBill <bill@gingerbill.org>2024-07-08 23:39:14 +0100
commit87ac68fcf2b5fcaa02118929b820e61bbd8c10c4 (patch)
treee39b1d5203b780d611a67f4bddb3e9c60689df4c /src
parent48aef5016499291996f0710449a26f1f92078d51 (diff)
Add `-internal-cached`
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp10
-rw-r--r--src/cached.cpp213
-rw-r--r--src/llvm_backend.cpp4
-rw-r--r--src/llvm_backend_general.cpp22
-rw-r--r--src/main.cpp26
-rw-r--r--src/string.cpp7
6 files changed, 265 insertions, 17 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index c8c83422f..be896f6fa 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -326,7 +326,12 @@ enum SanitizerFlags : u32 {
SanitizerFlag_Thread = 1u<<2,
};
-
+struct BuildCacheData {
+ u64 crc;
+ String cache_dir;
+ String manifest_path;
+ bool copy_already_done;
+};
// This stores the information for the specify architecture of this build
struct BuildContext {
@@ -427,6 +432,9 @@ struct BuildContext {
bool use_separate_modules;
bool module_per_file;
+ bool cached;
+ BuildCacheData build_cache_data;
+
bool no_threaded_checker;
bool show_debug_messages;
diff --git a/src/cached.cpp b/src/cached.cpp
new file mode 100644
index 000000000..89158ccbb
--- /dev/null
+++ b/src/cached.cpp
@@ -0,0 +1,213 @@
+gb_internal GB_COMPARE_PROC(cached_file_cmp) {
+ String const &x = *(String *)a;
+ String const &y = *(String *)b;
+ return string_compare(x, y);
+}
+
+
+u64 crc64_with_seed(void const *data, isize len, u64 seed) {
+ isize remaining;
+ u64 result = ~seed;
+ u8 const *c = cast(u8 const *)data;
+ for (remaining = len; remaining--; c++) {
+ result = (result >> 8) ^ (GB__CRC64_TABLE[(result ^ *c) & 0xff]);
+ }
+ return ~result;
+}
+
+bool check_if_exists_file_otherwise_create(String const &str) {
+ char const *str_c = alloc_cstring(permanent_allocator(), str);
+ if (!gb_file_exists(str_c)) {
+ gbFile f = {};
+ gb_file_create(&f, str_c);
+ gb_file_close(&f);
+ return true;
+ }
+ return false;
+}
+
+
+bool check_if_exists_directory_otherwise_create(String const &str) {
+#if defined(GB_SYSTEM_WINDOWS)
+ String16 wstr = string_to_string16(permanent_allocator(), str);
+ wchar_t *wstr_c = alloc_wstring(permanent_allocator(), wstr);
+ return CreateDirectoryW(wstr_c, nullptr);
+#else
+ char const *str_c = alloc_cstring(permanent_allocator(), str);
+ if (!gb_file_exists(str_c)) {
+ return false;
+ }
+ return false;
+#endif
+}
+bool try_copy_executable_cache_internal(bool to_cache) {
+ String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]);
+ defer (gb_free(heap_allocator(), exe_name.text));
+
+ gbString cache_name = gb_string_make(heap_allocator(), "");
+ defer (gb_string_free(cache_name));
+
+ String cache_dir = build_context.build_cache_data.cache_dir;
+
+ cache_name = gb_string_append_length(cache_name, cache_dir.text, cache_dir.len);
+ cache_name = gb_string_appendc(cache_name, "/");
+
+ cache_name = gb_string_appendc(cache_name, "cached-exe");
+ if (selected_target_metrics) {
+ cache_name = gb_string_appendc(cache_name, "-");
+ cache_name = gb_string_append_length(cache_name, selected_target_metrics->name.text, selected_target_metrics->name.len);
+ }
+ cache_name = gb_string_appendc(cache_name, ".bin");
+
+ if (to_cache) {
+ return gb_file_copy(
+ alloc_cstring(temporary_allocator(), exe_name),
+ cache_name,
+ false
+ );
+ } else {
+ return gb_file_copy(
+ cache_name,
+ alloc_cstring(temporary_allocator(), exe_name),
+ false
+ );
+ }
+}
+
+
+
+bool try_copy_executable_to_cache(void) {
+ if (try_copy_executable_cache_internal(true)) {
+ build_context.build_cache_data.copy_already_done = true;
+ return true;
+ }
+ return false;
+}
+
+bool try_copy_executable_from_cache(void) {
+ if (try_copy_executable_cache_internal(false)) {
+ build_context.build_cache_data.copy_already_done = true;
+ return true;
+ }
+ return false;
+}
+
+
+
+
+// returns false if different, true if it is the same
+bool try_cached_build(Checker *c) {
+ Parser *p = c->parser;
+
+ auto files = array_make<String>(heap_allocator());
+ for (AstPackage *pkg : p->packages) {
+ for (AstFile *f : pkg->files) {
+ array_add(&files, f->fullpath);
+ }
+ }
+
+ for (auto const &entry : c->info.load_file_cache) {
+ auto *cache = entry.value;
+ if (!cache || !cache->exists) {
+ continue;
+ }
+ array_add(&files, cache->path);
+ }
+
+ array_sort(files, cached_file_cmp);
+
+ u64 crc = 0;
+ for (String const &path : files) {
+ crc = crc64_with_seed(path.text, path.len, crc);
+ }
+
+ String base_cache_dir = build_context.build_paths[BuildPath_Output].basename;
+ base_cache_dir = concatenate_strings(permanent_allocator(), base_cache_dir, str_lit("/.odin-cache"));
+ (void)check_if_exists_directory_otherwise_create(base_cache_dir);
+
+ gbString crc_str = gb_string_make_reserve(permanent_allocator(), 16);
+ crc_str = gb_string_append_fmt(crc_str, "%016llx", crc);
+ String cache_dir = concatenate3_strings(permanent_allocator(), base_cache_dir, str_lit("/"), make_string_c(crc_str));
+ String manifest_path = concatenate3_strings(permanent_allocator(), cache_dir, str_lit("/"), str_lit("odin.manifest"));
+
+ build_context.build_cache_data.cache_dir = cache_dir;
+ build_context.build_cache_data.manifest_path = manifest_path;
+
+ if (check_if_exists_directory_otherwise_create(cache_dir)) {
+ goto do_write_file;
+ }
+
+ if (check_if_exists_file_otherwise_create(manifest_path)) {
+ goto do_write_file;
+ } else {
+ // exists already
+ LoadedFile loaded_file = {};
+
+ LoadedFileError file_err = load_file_32(
+ alloc_cstring(temporary_allocator(), manifest_path),
+ &loaded_file,
+ false
+ );
+ if (file_err) {
+ return false;
+ }
+
+ String data = {cast(u8 *)loaded_file.data, loaded_file.size};
+ String_Iterator it = {data, 0};
+
+ isize file_count = 0;
+
+ for (; it.pos < data.len; file_count++) {
+ String line = string_split_iterator(&it, '\n');
+ if (line.len == 0) {
+ break;
+ }
+ isize sep = string_index_byte(line, ' ');
+ if (sep < 0) {
+ goto do_write_file;
+ }
+
+ String timestamp_str = substring(line, 0, sep);
+ String path_str = substring(line, sep+1, line.len);
+
+ timestamp_str = string_trim_whitespace(timestamp_str);
+ path_str = string_trim_whitespace(path_str);
+
+ if (files[file_count] != path_str) {
+ goto do_write_file;
+ }
+
+ u64 timestamp = exact_value_to_u64(exact_value_integer_from_string(timestamp_str));
+ gbFileTime last_write_time = gb_file_last_write_time(alloc_cstring(temporary_allocator(), path_str));
+ if (last_write_time != timestamp) {
+ goto do_write_file;
+ }
+ }
+
+ if (file_count != files.count) {
+ goto do_write_file;
+ }
+
+ goto try_copy_executable;
+ }
+
+do_write_file:;
+ {
+ char const *manifest_path_c = alloc_cstring(temporary_allocator(), manifest_path);
+ gb_file_remove(manifest_path_c);
+
+ gbFile f = {};
+ defer (gb_file_close(&f));
+ gb_file_open_mode(&f, gbFileMode_Write, manifest_path_c);
+
+ for (String const &path : files) {
+ gbFileTime ft = gb_file_last_write_time(alloc_cstring(temporary_allocator(), path));
+ gb_fprintf(&f, "%llu %.*s\n", cast(unsigned long long)ft, LIT(path));
+ }
+ return false;
+ }
+
+try_copy_executable:;
+ return try_copy_executable_from_cache();
+}
+
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index 44b6e3839..b0df17778 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -1397,8 +1397,8 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
- gb_sort_array(m->global_types_to_create.data, m->global_types_to_create.count, llvm_global_entity_cmp);
- gb_sort_array(m->global_procedures_to_create.data, m->global_procedures_to_create.count, llvm_global_entity_cmp);
+ array_sort(m->global_types_to_create, llvm_global_entity_cmp);
+ array_sort(m->global_procedures_to_create, llvm_global_entity_cmp);
}
if (do_threading) {
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index 77f78a24c..bbeff562c 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -126,16 +126,17 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
m->gen = gen;
map_set(&gen->modules, cast(void *)pkg, m);
lb_init_module(m, c);
- if (module_per_file) {
- // NOTE(bill): Probably per file is not a good idea, so leave this for later
- for (AstFile *file : pkg->files) {
- auto m = gb_alloc_item(permanent_allocator(), lbModule);
- m->file = file;
- m->pkg = pkg;
- m->gen = gen;
- map_set(&gen->modules, cast(void *)file, m);
- lb_init_module(m, c);
- }
+ if (!module_per_file) {
+ continue;
+ }
+ // NOTE(bill): Probably per file is not a good idea, so leave this for later
+ for (AstFile *file : pkg->files) {
+ auto m = gb_alloc_item(permanent_allocator(), lbModule);
+ m->file = file;
+ m->pkg = pkg;
+ m->gen = gen;
+ map_set(&gen->modules, cast(void *)file, m);
+ lb_init_module(m, c);
}
}
}
@@ -144,7 +145,6 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
map_set(&gen->modules, cast(void *)1, &gen->default_module);
lb_init_module(&gen->default_module, c);
-
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
LLVMContextRef ctx = LLVMGetModuleContext(m->mod);
diff --git a/src/main.cpp b/src/main.cpp
index bbb326af3..006a7ddbc 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -71,6 +71,8 @@ gb_global Timings global_timings = {0};
#include "checker.cpp"
#include "docs.cpp"
+#include "cached.cpp"
+
#include "linker.cpp"
#if defined(GB_SYSTEM_WINDOWS) && defined(ODIN_TILDE_BACKEND)
@@ -391,6 +393,7 @@ enum BuildFlagKind {
BuildFlag_InternalIgnoreLLVMBuild,
BuildFlag_InternalIgnorePanic,
BuildFlag_InternalModulePerFile,
+ BuildFlag_InternalCached,
BuildFlag_Tilde,
@@ -594,6 +597,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalIgnorePanic, str_lit("internal-ignore-panic"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalModulePerFile, str_lit("internal-module-per-file"), BuildFlagParam_None, Command_all);
+ add_flag(&build_flags, BuildFlag_InternalCached, str_lit("internal-cached"), BuildFlagParam_None, Command_all);
#if ALLOW_TILDE
add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build);
@@ -1413,6 +1417,10 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_InternalModulePerFile:
build_context.module_per_file = true;
break;
+ case BuildFlag_InternalCached:
+ build_context.cached = true;
+ build_context.use_separate_modules = true;
+ break;
case BuildFlag_Tilde:
build_context.tilde_backend = true;
@@ -1921,9 +1929,6 @@ gb_internal void show_timings(Checker *c, Timings *t) {
gb_internal GB_COMPARE_PROC(file_path_cmp) {
AstFile *x = *(AstFile **)a;
AstFile *y = *(AstFile **)b;
- if (x == y) {
- return 0;
- }
return string_compare(x->fullpath, y->fullpath);
}
@@ -3322,6 +3327,13 @@ int main(int arg_count, char const **arg_ptr) {
return 0;
}
+ if (build_context.cached) {
+ MAIN_TIME_SECTION("check cached build");
+ if (try_cached_build(checker)) {
+ goto end_of_code_gen;
+ }
+ }
+
#if ALLOW_TILDE
if (build_context.tilde_backend) {
LinkerData linker_data = {};
@@ -3383,6 +3395,8 @@ int main(int arg_count, char const **arg_ptr) {
remove_temp_files(gen);
}
+end_of_code_gen:;
+
if (build_context.show_timings) {
show_timings(checker, &global_timings);
}
@@ -3391,6 +3405,12 @@ int main(int arg_count, char const **arg_ptr) {
export_dependencies(checker);
}
+
+ if (!build_context.build_cache_data.copy_already_done &&
+ build_context.cached) {
+ try_copy_executable_to_cache();
+ }
+
if (run_output) {
String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]);
defer (gb_free(heap_allocator(), exe_name.text));
diff --git a/src/string.cpp b/src/string.cpp
index ab08e3d4a..a39d93ad9 100644
--- a/src/string.cpp
+++ b/src/string.cpp
@@ -88,6 +88,13 @@ gb_internal char *alloc_cstring(gbAllocator a, String s) {
return c_str;
}
+gb_internal wchar_t *alloc_wstring(gbAllocator a, String16 s) {
+ wchar_t *c_str = gb_alloc_array(a, wchar_t, s.len+1);
+ gb_memmove(c_str, s.text, s.len*2);
+ c_str[s.len] = '\0';
+ return c_str;
+}
+
gb_internal gb_inline bool str_eq_ignore_case(String const &a, String const &b) {
if (a.len == b.len) {