Restructuring and add format strings typechecking for clang

This commit is contained in:
Krzosa Karol
2024-01-12 09:54:41 +01:00
parent a3c0a63ee2
commit f68500a804
13 changed files with 61 additions and 46 deletions

View File

@@ -1,362 +0,0 @@
/*
----------------- CL.EXE -----------------
FLAGS = /MP /Zi /FC /WX /W3 /wd4200 /diagnostics:column /nologo -D_CRT_SECURE_NO_WARNINGS /GF /Gm- /Oi
LINK = /link /incremental:no
STD_OFF = /GR- /EHa-
STD_ON = /EHsc
DEBUG = -Od -D_DEBUG -MDd -fsanitize=address -RTC1
DEBUG_LINK = -NODEFAULTLIB:LIBCMT
RELEASE = -O2 -MT -DNDEBUG -GL
RELEASE_LINK = -opt:ref -opt:icf
----------------- CL.EXE -----------------
/FC = Print full paths in diagnostics
/Gm- = Old feature, 'minimal compilation', in case it's not off by default
/GF = Pools strings as read-only. If you try to modify strings under /GF, an application error occurs.
/Oi = Replaces some function calls with intrinsic
/MP = Multithreaded compilation
/GR- = Disable runtime type information
/EHa- = Disable exceptions
/EHsc = Enable exceptions
/MT = Link static libc. The 'd' means debug version
/MD = Link dynamic libc. The 'd' means debug version
/GL = Whole program optimization
/RTC1 = runtime error checks
/opt:ref = eliminates functions and data that are never referenced
/opt:icf = eliminates redundant 'COMDAT's
*/
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "../core.c"
#define CL_Arena MA_Arena
#define CL_PushSize MA_PushSizeNonZeroed
#define CL_ASSERT IO_Assert
#define CL_VSNPRINTF stbsp_vsnprintf
#define CL_SNPRINTF stbsp_snprintf
#define AND_CL_STRING_TERMINATE_ON_NEW_LINE
#include "clexer.c"
#define SRC_CACHE_ENTRY_COUNT 1024
struct SRC_CacheEntry {
uint64_t filepath_hash;
uint64_t file_hash;
uint64_t includes_hash;
uint64_t total_hash;
};
struct SRC_Cache {
int entry_cap;
int entry_len;
SRC_CacheEntry entries[SRC_CACHE_ENTRY_COUNT];
};
double SRC_Time;
SRC_Cache *SRC_InMemoryCache;
SRC_Cache *SRC_FromFileCache;
CL_ArenaTuple SRC_ArenaTuple;
S8_String SRC_CacheFilename;
MA_Arena PernamentArena;
MA_Arena *Perm = &PernamentArena;
CL_SearchPaths SRC_SearchPaths = {}; // @todo;
Table<S8_String> CMDLine;
void SRC_InitCache(MA_Arena *arena, S8_String cachefilename) {
SRC_CacheFilename = cachefilename;
CL_InitDefaultTuple(&SRC_ArenaTuple);
SRC_InMemoryCache = MA_PushStruct(arena, SRC_Cache);
SRC_InMemoryCache->entry_cap = SRC_CACHE_ENTRY_COUNT;
SRC_FromFileCache = MA_PushStruct(arena, SRC_Cache);
SRC_FromFileCache->entry_cap = SRC_CACHE_ENTRY_COUNT;
S8_String cache = OS_ReadFile(arena, SRC_CacheFilename);
if (cache.len) MA_MemoryCopy(SRC_FromFileCache, cache.str, cache.len);
}
void SRC_SaveCache() {
S8_String dump = S8_Make((char *)SRC_InMemoryCache, sizeof(SRC_Cache));
OS_WriteFile(SRC_CacheFilename, dump);
}
SRC_CacheEntry *SRC_AddHash(uint64_t filepath, uint64_t file, uint64_t includes) {
IO_Assert(SRC_InMemoryCache->entry_len + 1 < SRC_InMemoryCache->entry_cap);
SRC_CacheEntry *result = SRC_InMemoryCache->entries + SRC_InMemoryCache->entry_len++;
result->filepath_hash = filepath;
result->file_hash = file;
result->includes_hash = includes;
result->total_hash = HashBytes(result, sizeof(uint64_t) * 3);
return result;
}
SRC_CacheEntry *SRC_FindCache(SRC_Cache *cache, uint64_t filepath_hash) {
for (int cache_i = 0; cache_i < cache->entry_len; cache_i += 1) {
SRC_CacheEntry *it = cache->entries + cache_i;
if (it->filepath_hash == filepath_hash) {
return it;
}
}
return 0;
}
SRC_CacheEntry *SRC_HashFile(S8_String file, char *parent_file) {
char *resolved_file = CL_ResolveFilepath(Perm, &SRC_SearchPaths, file.str, parent_file, false);
if (!resolved_file) {
IO_Printf("Failed to resolve file: %s\n", file.str);
return 0;
}
uint64_t filepath_hash = HashBytes(resolved_file, S8_Length(resolved_file));
SRC_CacheEntry *entry = SRC_FindCache(SRC_InMemoryCache, filepath_hash);
if (entry) return entry;
CL_LexResult *first_lex = CL_LexFile(&SRC_ArenaTuple, resolved_file);
IO_Assert(first_lex);
uint64_t file_hash = HashBytes(first_lex->stream_begin, first_lex->stream - first_lex->stream_begin);
uint64_t includes_hash = 13;
CL_LexList list = CL_MakeLexList(first_lex);
for (CL_IncludeIter iter = CL_IterateIncludes(&list); iter.filename; CL_GetNextInclude(&iter)) {
if (iter.is_system_include) continue;
S8_String file_it = S8_MakeFromChar(iter.filename);
SRC_CacheEntry *cache = SRC_HashFile(file_it, resolved_file);
if (!cache) {
IO_Printf("Missing cache for: %s\n", file_it.str);
continue;
}
includes_hash = HashMix(includes_hash, cache->total_hash);
}
SRC_CacheEntry *result = SRC_AddHash(filepath_hash, file_hash, includes_hash);
return result;
}
bool SRC_WasModified(S8_String file, S8_String artifact_path) {
double time_start = OS_GetTime();
if (OS_FileExists(file) == false) {
IO_Printf("FAILED File doesnt exist: %.*s\n", S8_Expand(file));
exit(0);
}
if (OS_IsAbsolute(file) == false) {
file = OS_GetAbsolutePath(Perm, file);
}
S8_String without_ext = S8_ChopLastPeriod(file);
S8_String name_only = S8_SkipToLastSlash(without_ext);
if (artifact_path.len == 0) artifact_path = S8_Format(Perm, "%.*s.%s", S8_Expand(name_only), IF_WINDOWS_ELSE("obj", "o"));
bool modified = OS_FileExists(artifact_path) == false;
SRC_CacheEntry *in_memory = SRC_HashFile(file, 0);
IO_Assert(in_memory);
if (modified == false) {
SRC_CacheEntry *from_file = SRC_FindCache(SRC_FromFileCache, in_memory->filepath_hash);
if (from_file == 0 || (in_memory->total_hash != from_file->total_hash)) {
modified = true;
}
}
SRC_Time = SRC_Time + (OS_GetTime() - time_start);
return modified;
}
//
//
//
using Str = S8_String;
struct Strs : Array<Str> {
Strs() = default;
Strs(char *str) {
*this = {};
this->add(S8_MakeFromChar(str));
}
Strs(char *a, char *b) {
*this = {};
this->add(S8_MakeFromChar(a));
this->add(S8_MakeFromChar(b));
}
Strs(char *a, char *b, char *c) {
*this = {};
this->add(S8_MakeFromChar(a));
this->add(S8_MakeFromChar(b));
this->add(S8_MakeFromChar(c));
}
Strs(Str a) {
*this = {};
this->add(a);
}
Strs(Array<Str> a) { MA_MemoryCopy(this, &a, sizeof(a)); }
};
bool operator==(Strs a, char *b) {
if (a.len != 1) return false;
bool result = a[0] == S8_MakeFromChar(b);
return result;
}
bool operator==(Strs a, const char *b) {
if (a.len != 1) return false;
bool result = a[0] == S8_MakeFromChar((char *)b);
return result;
}
Strs operator+(Strs a, Strs b) {
Strs c = {a.copy(*Perm)};
c.add_array(b);
return c;
}
Strs operator+(Strs a, Str b) {
Strs c = {a.copy(*Perm)};
c.add(b);
return c;
}
Strs operator+(Str a, Strs b) {
Strs c = {b.copy(*Perm)};
c.add(a);
return c;
}
Strs &operator+=(Strs &a, Strs b) {
a.add_array(b);
return a;
}
Strs &operator+=(Strs &a, char *str) {
a.add(S8_MakeFromChar(str));
return a;
}
Strs &operator+=(Strs &a, Str s) {
a.add(s);
return a;
}
Strs operator+(Strs a, char *b) {
Strs c = {a.copy(*Perm)};
c.add(S8_MakeFromChar(b));
return c;
}
Strs operator+(char *a, Strs b) {
Strs c = {b.copy(*Perm)};
c.add(S8_MakeFromChar(a));
return c;
}
Strs operator+(Str a, Str b) {
Strs c = {};
c.add(a);
c.add(b);
return c;
}
Strs operator+(Str a, char *b) {
return a + S8_MakeFromChar(b);
}
//@todo: split on any whitespace instead!
Strs Split(char *str) {
Str s = S8_MakeFromChar(str);
S8_List list = S8_Split(Perm, s, S8_Lit(" "), 0);
Strs result = {};
S8_For(it, list) result.add(it->string);
return result;
}
Str Merge(Strs list, Str separator = " "_s) {
int64_t char_count = 0;
For(list) char_count += it.len;
if (char_count == 0) return {};
int64_t node_count = list.len;
int64_t base_size = (char_count + 1);
int64_t sep_size = (node_count - 1) * separator.len;
int64_t size = base_size + sep_size;
char *buff = (char *)MA_PushSize(Perm, sizeof(char) * size);
Str string = S8_Make(buff, 0);
For(list) {
IO_Assert(string.len + it.len <= size);
MA_MemoryCopy(string.str + string.len, it.str, it.len);
string.len += it.len;
if (!list.is_last(it)) {
MA_MemoryCopy(string.str + string.len, separator.str, separator.len);
string.len += separator.len;
}
}
IO_Assert(string.len == size - 1);
string.str[size] = 0;
return string;
}
S8_String FilenameWithoutExt(S8_String it) { return S8_SkipToLastSlash(S8_ChopLastPeriod(it)); }
bool CodeWasModified(char *str, char *artifact = 0) { return SRC_WasModified(S8_MakeFromChar(str), S8_MakeFromChar(artifact)); }
bool CodeWasModified(S8_String str, S8_String artifact = {}) { return SRC_WasModified(str, artifact); }
Strs IfCodeWasModified(char *cfile, char *objfile) {
Strs result = {};
S8_String s = S8_MakeFromChar(cfile);
S8_String o = S8_MakeFromChar(objfile);
if (SRC_WasModified(s, o)) {
return cfile;
}
return objfile;
}
void MakeDir(char *str) { OS_MakeDir(S8_MakeFromChar(str)); }
void ChangeDir(char *str) { OS_SetWorkingDir(S8_MakeFromChar(str)); }
int Run(Strs s) {
Str cmd = Merge(s);
return OS_SystemF("%Q", cmd);
}
Strs ListDir(char *dir) {
Strs result = {};
S8_List files = OS_ListDir(Perm, S8_MakeFromChar(dir), 0);
S8_For(it, files) result.add(it->string);
return result;
}
void ReportError(S8_String it) {
IO_FatalErrorf("Invalid command line argument syntax! Expected a key value pair!\n"
"Here is the wrong argument: %Q\n"
"Here is a good example: bld.exe profile=release platform=windows\n",
it);
}
#ifndef BUILD_MAIN
int Main();
int main(int argc, char **argv) {
if (argc > 1) IO_Printf("Command line arguments:\n");
for (int i = 1; i < argc; i += 1) {
S8_String it = S8_MakeFromChar(argv[i]);
int64_t idx = 0;
if (S8_Find(it, "="_s, 0, &idx)) {
S8_String key = S8_GetPrefix(it, idx);
S8_String value = S8_Skip(it, idx + 1);
if (key.len == 0) ReportError(it);
if (value.len == 0) ReportError(it);
IO_Printf("[%d] %Q = %Q\n", i, key, value);
CMDLine.put(key, value);
}
else ReportError(it);
}
SRC_InitCache(Perm, S8_Lit("build_file.cache"));
int result = Main();
if (result == 0) SRC_SaveCache();
return result;
}
#endif

View File

@@ -1,83 +0,0 @@
#define BUILD_MAIN
#include "build_lib.cpp"
int main(int argument_count, char **arguments) {
OS_MakeDir(S8_Lit("build"));
OS_SetWorkingDir(S8_Lit("build"));
IO_Printf("WORKING DIR: %Q\n", OS_GetWorkingDir(Perm));
S8_String cc = ON_WINDOWS("cl"_s) ON_MAC("clang"_s) ON_LINUX("gcc"_s);
S8_String cache_filename = "build_tool.cache"_s;
S8_String cmdline_args = S8_MakeEmpty();
for (int i = 1; i < argument_count; i += 1) {
S8_String arg = S8_MakeFromChar(arguments[i]);
if (arg == "clear_cache"_s) {
OS_DeleteFile(cache_filename);
break;
}
cmdline_args = S8_Format(Perm, "%Q%Q ", cmdline_args, arg);
}
SRC_InitCache(Perm, cache_filename);
// Search for build file in the project directory
S8_String build_file = {0};
{
S8_List files_current_dir = OS_ListDir(Perm, S8_Lit(".."), 0);
for (S8_Node *it = files_current_dir.first; it; it = it->next) {
if (S8_Find(it->string, S8_Lit("build_file.c"), S8_IGNORE_CASE, 0)) {
build_file = it->string;
}
}
if (build_file.str == 0) {
IO_Printf("IDLE Nothing to do, couldnt find build file in current dir: %Q, exiting ... \n", OS_GetWorkingDir(Perm));
return 0;
}
}
S8_String a = S8_ChopLastPeriod(build_file);
S8_String b = S8_SkipToLastSlash(a);
S8_String exe_name = S8_Format(Perm, "%Q.exe", b);
// @todo: add search path?
// Compile the build file only if code changed
if (SRC_WasModified(build_file, exe_name)) {
double time = OS_GetTime();
int result = 0;
if (cc == "cl"_s) {
result = OS_SystemF("cl %Q -Fe:%Q -WX -W3 -wd4200 -diagnostics:column -nologo -Zi", build_file, exe_name);
}
else if (cc == "clang"_s) {
result = OS_SystemF("clang++ -std=c++11 -Wno-writable-strings %Q -o %Q -g", build_file, exe_name);
}
else {
IO_Assert(cc == "gcc"_s);
result = OS_SystemF("gcc -Wno-write-strings %Q -o %Q -g", build_file, exe_name);
}
if (result != 0) {
IO_Printf("FAILED compilation of the build file!\n");
return 1;
}
time = OS_GetTime() - time;
IO_Printf("TIME Build file compilation: %f\n", time);
}
// Run the build file
double time = OS_GetTime();
if (build_file.str) {
int result = OS_SystemF(IF_WINDOWS_ELSE("", "./") "%Q %Q", exe_name, cmdline_args);
if (result != 0) {
printf("FAILED execution of the build file!\n");
return 1;
}
}
time = OS_GetTime() - time;
IO_Printf("TIME total build file execution: %f\n", time);
SRC_SaveCache();
// OS_SetWorkingDir(S8_Lit(".."));
}

View File

@@ -169,7 +169,8 @@ OS_API S8_List OS_ListDir(MA_Arena *arena, S8_String path, unsigned flags) {
bool dir = ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
S8_String filename = UTF_CreateStringFromWidechar(scratch.arena, ffd.cFileName, S8_WideLength(ffd.cFileName));
S8_String rel_abs_path = S8_Format(scratch.arena, "%Q/%Q%Q", it->string, filename, dir ? S8_Lit("/") : S8_Lit(""));
S8_String is_dir = dir ? S8_Lit("/") : S8_Lit("");
S8_String rel_abs_path = S8_Format(scratch.arena, "%.*s/%.*s%.*s", S8_Expand(it->string), S8_Expand(filename), S8_Expand(is_dir));
if (flags & OS_RELATIVE_PATHS) {
S8_Add(arena, &result, rel_abs_path);
}
@@ -498,12 +499,12 @@ OS_API S8_List OS_ListDir(MA_Arena *arena, S8_String path, unsigned flags) {
continue;
}
S8_String n = S8_Format(scratch.arena, "%Q/%s", path, dir->d_name);
S8_String n = S8_Format(scratch.arena, "%.*s/%s", S8_Expand(path), dir->d_name);
if ((flags & OS_RELATIVE_PATHS) == 0) {
n = OS_GetAbsolutePath(scratch.arena, n);
}
if (dir->d_type == DT_DIR) {
n = S8_Format(scratch.arena, "%Q/", n);
n = S8_Format(scratch.arena, "%.*s/", S8_Expand(n));
}
S8_AddNode(arena, &result, S8_Copy(arena, n));
@@ -525,18 +526,18 @@ OS_API OS_Result OS_MakeDir(S8_String path) {
OS_API OS_Result OS_CopyFile(S8_String from, S8_String to, bool overwrite) {
const char *ow = overwrite ? "-n" : "";
int result = OS_SystemF("cp %s %Q %Q", ow, from, to);
int result = OS_SystemF("cp %s %.*s %.*s", ow, S8_Expand(from), S8_Expand(to));
return result == 0 ? OS_SUCCESS : OS_FAILURE;
}
OS_API OS_Result OS_DeleteFile(S8_String path) {
int result = OS_SystemF("rm %Q");
int result = OS_SystemF("rm %.*s", S8_Expand(path));
return result == 0 ? OS_SUCCESS : OS_FAILURE;
}
OS_API OS_Result OS_DeleteDir(S8_String path, unsigned flags) {
IO_Assert(flags & OS_RECURSIVE);
int result = OS_SystemF("rm -r %Q");
int result = OS_SystemF("rm -r %.*s", S8_Expand(path));
return result == 0 ? OS_SUCCESS : OS_FAILURE;
}

View File

@@ -9,15 +9,11 @@
#endif
#endif
//@begin gen_structs
typedef struct RandomSeed RandomSeed;
//@end gen_structs
struct RandomSeed {
uint64_t a;
};
//@begin gen_api_funcs
HASH_API_FUNCTION uint64_t HashBytes(void *data, uint64_t size);
HASH_API_FUNCTION RandomSeed MakeRandomSeed(uint64_t value);
HASH_API_FUNCTION uint64_t GetRandomU64(RandomSeed *state);
@@ -25,7 +21,6 @@ HASH_API_FUNCTION int GetRandomRangeI(RandomSeed *seed, int first, int last_incl
HASH_API_FUNCTION double GetRandomNormal(RandomSeed *series);
HASH_API_FUNCTION double GetRandomNormalRange(RandomSeed *seed, double min, double max);
HASH_API_FUNCTION uint64_t HashMix(uint64_t x, uint64_t y);
//@end gen_api_funcs
#define WRAP_AROUND_POWER_OF_2(x, pow2) (((x) & ((pow2)-1llu)))
static inline float GetRandomNormalF(RandomSeed *series) { return (float)GetRandomNormal(series); }

View File

@@ -21,6 +21,16 @@ typedef enum IO_ErrorResult {
#define IO_DebugBreak() (IO_Exit(1), 0)
#endif
#if defined(__has_attribute)
#if __has_attribute(format)
#define IO__PrintfFormat(fmt, va) __attribute__((format(printf, fmt, va)))
#endif
#endif
#ifndef IO__PrintfFormat
#define IO__PrintfFormat(fmt, va)
#endif
extern void (*IO_User_OutputMessage)(char *str, int len);
#define IO__STRINGIFY(x) #x
@@ -63,8 +73,8 @@ extern void (*IO_User_OutputMessage)(char *str, int len);
}
#define IO_Todo() IO_FatalError("This codepath is not implemented yet")
IO_API bool IO__FatalErrorf(const char *file, int line, const char *msg, ...);
IO_API void IO_Printf(const char *msg, ...);
IO_API bool IO__FatalErrorf(const char *file, int line, const char *msg, ...) IO__PrintfFormat(3, 4);
IO_API void IO_Printf(const char *msg, ...) IO__PrintfFormat(1, 2);
IO_API bool IO__FatalError(char *msg);
IO_API void IO_Print(char *msg);
IO_API void IO_OutputMessage(char *str, int len);

View File

@@ -14,7 +14,7 @@ LIB_Library LIB_LoadLibrary(char *str) {
}
void *LIB_LoadSymbol(LIB_Library lib, char *symbol) {
void *result = GetProcAddress((HMODULE)lib, symbol);
void *result = (void *)GetProcAddress((HMODULE)lib, symbol);
return result;
}

View File

@@ -44,6 +44,16 @@ enum {
S8_MATCH_FIND_LAST = 32,
};
#if defined(__has_attribute)
#if __has_attribute(format)
#define S8__PrintfFormat(fmt, va) __attribute__((format(printf, fmt, va)))
#endif
#endif
#ifndef S8__PrintfFormat
#define S8__PrintfFormat(fmt, va)
#endif
#define S8_Lit(string) S8_Make((char *)string, sizeof(string) - 1)
#define S8_ConstLit(string) \
{ string, sizeof(string) - 1 }
@@ -104,7 +114,7 @@ S8_API S8_String S8_MakeFromChar(char *string);
S8_API S8_String S8_MakeEmpty(void);
S8_API S8_List S8_MakeEmptyList(void);
S8_API S8_String S8_FormatV(S8_Allocator allocator, const char *str, va_list args1);
S8_API S8_String S8_Format(S8_Allocator allocator, const char *str, ...);
S8_API S8_String S8_Format(S8_Allocator allocator, const char *str, ...) S8__PrintfFormat(2, 3);
S8_API S8_Node *S8_CreateNode(S8_Allocator allocator, S8_String string);
S8_API void S8_ReplaceNodeString(S8_List *list, S8_Node *node, S8_String new_string);
S8_API void S8_AddExistingNode(S8_List *list, S8_Node *node);
@@ -115,4 +125,4 @@ S8_API S8_List S8_CopyList(S8_Allocator allocator, S8_List a);
S8_API S8_List S8_ConcatLists(S8_Allocator allocator, S8_List a, S8_List b);
S8_API S8_Node *S8_AddNode(S8_Allocator allocator, S8_List *list, S8_String string);
S8_API S8_Node *S8_Add(S8_Allocator allocator, S8_List *list, S8_String string);
S8_API S8_String S8_AddF(S8_Allocator allocator, S8_List *list, const char *str, ...);
S8_API S8_String S8_AddF(S8_Allocator allocator, S8_List *list, const char *str, ...) S8__PrintfFormat(3, 4);

View File

@@ -38,10 +38,10 @@
#define TABLE_ASSERT(x) assert(x)
#endif
#ifndef TABLE_SET_DEFAULT_ALLOCATOR
#define TABLE_SET_DEFAULT_ALLOCATOR
// Example:
// #define TABLE_SET_DEFAULT_ALLOCATOR if (!allocator) allocator = global_heap;
#ifndef TABLE_SET_DEFAULT_ALLOCATOR
#define TABLE_SET_DEFAULT_ALLOCATOR
#endif
#ifndef TABLE_HASH_BYTES