From 1f2853f8cd9bf836aa5ef18eb3f25e537a567419 Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Sat, 16 May 2026 19:18:40 +0200 Subject: [PATCH 01/11] Move build script logic to cpp --- build.bat | 26 ++ build.sh | 28 ++ code/4ed_build.cpp | 577 ++++++++++++++++++++++++++++ code/bin/4ed_build.cpp | 611 ------------------------------ code/bin/build-linux.sh | 35 -- code/bin/build-mac.sh | 35 -- code/bin/build.bat | 52 --- code/bin/build_optimized.bat | 3 - code/bin/detect_os.sh | 9 - code/custom/4coder_base_types.cpp | 14 + 10 files changed, 645 insertions(+), 745 deletions(-) create mode 100644 build.bat create mode 100644 build.sh create mode 100644 code/4ed_build.cpp delete mode 100644 code/bin/4ed_build.cpp delete mode 100755 code/bin/build-linux.sh delete mode 100755 code/bin/build-mac.sh delete mode 100644 code/bin/build.bat delete mode 100644 code/bin/build_optimized.bat delete mode 100755 code/bin/detect_os.sh diff --git a/build.bat b/build.bat new file mode 100644 index 000000000..14a6b63d6 --- /dev/null +++ b/build.bat @@ -0,0 +1,26 @@ +@echo off + +rem Make sure we are at the root of the project +cd /D "%~dp0" + +set src_root=%cd%\code +set custom_root=%src_root%\custom +set build_root=%cd%\build + +if "%PROCESSOR_ARCHITECTURE%" == "AMD64" ( + call %custom_root%\bin\setup_cl_x64.bat +) else ( + call %custom_root%\bin\setup_cl_x86.bat +) + +set opts=/nologo /FC /Zi /I%src_root% /I%custom_root% + +if not exist "%build_root%" mkdir %build_root% +pushd %build_root% +call cl %opts% %src_root%\4ed_build.cpp /Febuild +if %ERRORLEVEL% neq 0 exit /b +popd + +pushd %src_root% +%build_root%\build.exe %* +popd diff --git a/build.sh b/build.sh new file mode 100644 index 000000000..9724dfe8b --- /dev/null +++ b/build.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -e + +# Make sure we are at the root of the project +cd "$(realpath "$(dirname "$0")")" + +SRC_ROOT="$PWD/code" +CUSTOM_ROOT="$SRC_ROOT/custom" +BUILD_ROOT="$PWD/build" + +if [[ -z "$CC" ]]; then + CC=c++ +fi + +CFLAGS="-D_GNU_SOURCE -fPIC -fpermissive -Wno-write-strings -Wno-comment" +CFLAGS="$CFLAGS -Wno-null-dereference -Wno-logical-op-parentheses -Wno-switch" +CFLAGS="$CFLAGS -I$SRC_ROOT -I$CUSTOM_ROOT" + +if [[ ! -d "$BUILD_ROOT" ]]; then + mkdir -p "$BUILD_ROOT" +fi + +eval "$CC $CFLAGS $SRC_ROOT/4ed_build.cpp -g -o $BUILD_ROOT/build" + +pushd "$SRC_ROOT" +"$BUILD_ROOT/build" $* +popd diff --git a/code/4ed_build.cpp b/code/4ed_build.cpp new file mode 100644 index 000000000..d7df25329 --- /dev/null +++ b/code/4ed_build.cpp @@ -0,0 +1,577 @@ +/* + * 4coder development build rule. + */ + +#include "4coder_base_types.h" + +#include "4coder_base_types.cpp" +#include "4coder_malloc_allocator.cpp" + +#define FTECH_FILE_MOVING_IMPLEMENTATION +#include "4coder_file_moving.h" + +#define ForEachNode(NAME, LIST) \ + for (auto* NAME = (LIST)->first; NAME != NULL; NAME = NAME->next) + +// Constants + +static char* BUILD_ROOT; +static char* SRC_ROOT; +static char* NON_SRC_ROOT; +static char* CUSTOM_ROOT; +static char* FOREIGN_ROOT; + +// Build Options + +enum { + OPTS = bit_1, + LIBS = bit_2, + ICON = bit_3, + SHARED_CODE = bit_4, + DEBUG_INFO = bit_5, + OPTIMIZATION = bit_6, + SUPER = bit_7, + INTERNAL = bit_8, + SHIP = bit_9, + VERBOSE = bit_10, +}; + +enum GLAPI { + GLAPI_OPENGL, + GLAPI_DX11, +}; + +enum BuildMode { + MODE_DEBUG = DEBUG_INFO | INTERNAL, + MODE_RELEASE = OPTIMIZATION | SHIP, + MODE_RELEASE_DEBINFO = MODE_DEBUG | MODE_RELEASE, +}; + +struct BuildFlags { + BuildMode type = MODE_DEBUG; + GLAPI backend = GLAPI_OPENGL; + u32 opts = 0; +}; + +#if COMPILER_CL && OS_WINDOWS ///////////////////////////////////////////////////////////////////// + +void build( + Arena *arena, + const char* out_file, + List_String_Const_char files, + List_String_Const_char defines, + List_String_Const_char exports, + List_String_Const_char includes, + BuildFlags flags +) { + Temp_Dir temp = fm_pushdir(BUILD_ROOT); + + Build_Line line; + fm_init_build_line(&line); + + fm_add_to_line(line, "cl"); + + if (flags.opts & OPTS){ + const char* opts[] = { + "-W4", // Enables all warnings + "-WX", // Raise warnings to errors + "-nologo", // Suppress copyright message + "-FC", // Use full pathnames in diagnostics + "-GR-", // Disable Runtime Type informations + "-EHa-", // Disable C++ EH (w/ SEH exceptions) + "-wd4310", // Disable "cast truncates constant value" + "-wd4100", // Disable "'identifier' : unreferenced formal parameter" + "-wd4201", // Disable "nonstandard extension used : nameless struct/union " + "-wd4505", // Disable "'function' : unreferenced local function has been removed" + "-wd4996", // Disable "deprecation warnings" + "-wd4127", // Disable "conditional expression is constant" + "-wd4510", // Disable "'class': default constructor was implicitly defined as deleted" + "-wd4512", // Disable "'class' : assignment operator could not be generated " + "-wd4610", // Disable "object 'class' can never be instantiated - user-defined constructor required" + "-wd4390", // Disable "';' : empty controlled statement found; is this the intent?" + "-wd4611", // Disable "interaction between 'function' and C++ object destruction is non-portable" + "-wd4189", // Disable "'identifier' : local variable is initialized but not referenced" + }; + + for (int i = 0; i < ArrayCount(opts); ++i) + fm_add_to_line(line, "%s", opts[i]); + } + + if (flags.opts & LIBS) { + fm_add_to_line(line, "%s", "user32.lib winmm.lib gdi32.lib comdlg32.lib userenv.lib"); + + if (ARCH_X64) { + fm_add_to_line(line, "%s", fm_str(arena, FOREIGN_ROOT, "\\x64\\freetype.lib")); + } else if (ARCH_X86) { + fm_add_to_line(line, "%s", fm_str(arena, FOREIGN_ROOT, "\\x86\\freetype.lib")); + } else { + InvalidPath; + } + + switch (flags.backend) { + case GLAPI_OPENGL: + fm_add_to_line(line, "OpenGL32.lib"); + break; + case GLAPI_DX11: + fm_add_to_line(line, "d3d11.lib dxgi.lib d3dcompiler.lib"); + break; + default: + InvalidPath; + } + } + + if (flags.opts & ICON) + fm_add_to_line(line, "..\\non-source\\res\\icon.res"); + + if (flags.opts & DEBUG_INFO) { + fm_add_to_line(line, "-Zi"); + fm_add_to_line(line, "-DDO_CRAZY_EXPENSIVE_ASSERTS"); + } + + if (flags.opts & OPTIMIZATION) + fm_add_to_line(line, "-O2"); + + if (flags.opts & SHARED_CODE) + fm_add_to_line(line, "-LD"); + + ForEachNode(iter, &includes) { + fm_add_to_line(line, "-I%.*s", string_expand(iter->string)); + } + + ForEachNode(iter, &defines) { + fm_add_to_line(line, "-D%.*s", string_expand(iter->string)); + } + + ForEachNode(iter, &files) { + fm_add_to_line(line, "\"%.*s\"", string_expand(iter->string)); + } + + fm_add_to_line(line, "-Fe%s", out_file); + + fm_add_to_line(line, "-link -INCREMENTAL:NO -RELEASE -PDBALTPATH:%%_PDB%%"); + + if (ARCH_X64) { + fm_add_to_line(line, "-MACHINE:X64"); + } else if (ARCH_X86) { + fm_add_to_line(line, "-MACHINE:X86"); + } else { + InvalidPath; + } + + if (flags.opts & DEBUG_INFO){ + fm_add_to_line(line, "-DEBUG"); + } + + if (flags.opts & SHARED_CODE) { + fm_add_to_line(line, "-OPT:REF"); + ForEachNode(iter, &exports) { + fm_add_to_line(line, "-EXPORT:%.*s", string_expand(iter->string)); + } + } else { + fm_add_to_line(line, "-NODEFAULTLIB:library"); + } + + fm_finish_build_line(&line); + + if (flags.opts & VERBOSE) { + printf("%s\n", line.build_options); + } + + systemf("%s", line.build_options); + fm_popdir(temp); +} + +#elif COMPILER_GCC && OS_LINUX //////////////////////////////////////////////////////////////////// + +void build( + Arena *arena, + const char* out_file, + List_String_Const_char files, + List_String_Const_char defines, + List_String_Const_char exports, + List_String_Const_char includes, + BuildFlags flags +) { + Temp_Dir temp = fm_pushdir(BUILD_ROOT); + + Build_Line line; + fm_init_build_line(&line); + + fm_add_to_line(line, "g++"); + + if (flags.opts & OPTS) { + const char* opts[] = { + "-D_GNU_SOURCE", // Enable GNU extentions + "-fPIC", // Enable Position Independent Code + "-fno-threadsafe-statics -pthread", // Don't use C++ thread safety routines + "-Wno-write-strings", // Disable "warning: deprecated conversion from string constant to 'char*'" + "-Wno-unused-result", // Disable "warning: ignoring return value of 'function_name'" + "-std=c++11", + }; + + for (int i = 0; i < ArrayCount(opts); ++i) + fm_add_to_line(line, "%s", opts[i]); + } + + if (flags.opts & DEBUG_INFO) { + fm_add_to_line(line, "-g -O0"); + } + + if (flags.opts & OPTIMIZATION) { + fm_add_to_line(line, "-O3"); + } + + if (flags.opts & SHARED_CODE) { + fm_add_to_line(line, "-shared"); + } + + ForEachNode(iter, &defines) { + fm_add_to_line(line, "-D%.*s", string_expand(iter->string)); + } + + ForEachNode(iter, &includes) { + fm_add_to_line(line, "-I%.*s", string_expand(iter->string)); + } + + ForEachNode(iter, &files) { + fm_add_to_line(line, "'%.*s'", string_expand(iter->string)); + } + + if (flags.opts & LIBS) { + fm_add_to_line(line, "-lX11 -lpthread -lm -lrt -lGL -ldl -lXfixes -lfreetype -lfontconfig"); + } + + fm_add_to_line(line, "-o %s", out_file); + + fm_finish_build_line(&line); + + if (flags.opts & VERBOSE) { + printf("%s\n", line.build_options); + } + + systemf("%s", line.build_options); + fm_popdir(temp); +} + +#elif COMPILER_CLANG && OS_MAC //////////////////////////////////////////////////////////////////// + +void build( + Arena *arena, + const char* out_file, + List_String_Const_char files, + List_String_Const_char defines, + List_String_Const_char exports, + List_String_Const_char includes, + BuildFlags flags +) { + Temp_Dir temp = fm_pushdir(BUILD_ROOT); + + Build_Line line; + fm_init_build_line(&line); + + fm_add_to_line(line, "clang++"); + + if (flags.opts & OPTS){ + const char* opts[] = { + "-Wno-write-strings", // Disable "warning: deprecated conversion from string constant to 'char*'" + "-Wno-deprecated-declarations", // Disable deprecation warnings + "-Wno-switch", // Disable "enumeration value B not handled in switch" + "-Wno-null-dereference", // Disable "warning: binding dereferenced null pointer to reference has undefined behavior" + "-Wno-unused-result", // Disable "warning: ignoring return value of 'function_name'" + "-Wno-missing-declarations", // Disable "warning: declaration does not declare anything" + "-Wno-nullability-completeness", // Disable "warning: pointer is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)" + "-Wno-tautological-compare", + "-std=c++11 ", + }; + + for (int i = 0; i < ArrayCount(opts); ++i) + fm_add_to_line(line, "%s", opts[i]); + } + + if (flags.opts & DEBUG_INFO){ + fm_add_to_line(line, "-g -O0"); + } + + if (flags.opts & OPTIMIZATION){ + fm_add_to_line(line, "-O3"); + } + + if (flags.opts & SHARED_CODE){ + fm_add_to_line(line, "-shared"); + } + + ForEachNode(iter, &includes) { + fm_add_to_line(line, "-I%.*s", string_expand(iter->string)); + } + + ForEachNode(iter, &defines) { + fm_add_to_line(line, "-D%.*s", string_expand(iter->string)); + } + + ForEachNode(iter, &files) { + fm_add_to_line(line, "'%.*s'", string_expand(iter->string)); + } + + if (flags.opts & LIBS) { + fm_add_to_line(line, "-framework Cocoa -framework QuartzCore " + "-framework CoreServices -framework OpenGL " + "-framework IOKit -framework Metal " + "-framework MetalKit"); + + if (ARCH_X64) { + fm_add_to_line(line, "%s", fm_str(arena, FOREIGN_ROOT, "/x64/libfreetype-mac.a")); + } else if (ARCH_X86) { + fm_add_to_line(line, "%s", fm_str(arena, FOREIGN_ROOT, "/x86/libfreetype-mac.a")); + } else { + InvalidPath; + } + } + + fm_add_to_line(line, "-o %s", out_file); + + fm_finish_build_line(&line); + + if (flags.opts & VERBOSE) { + printf("%s\n", line.build_options); + } + + systemf("%s", line.build_options); + fm_popdir(temp); +} + +#else +# error build function not defined for this compiler +#endif //////////////////////////////////////////////////////////////////////////////////////////// + +function void +dispatch_build(Arena* arena, BuildFlags flags) { + // Build Super + { + Temp_Dir dir = fm_pushdir(BUILD_ROOT); + + const char* build_script = fm_str(arena, CUSTOM_ROOT, "/bin/buildsuper_", ARCH_NAME, "-" OS_NAME, BAT); + char* default_custom_target = fm_str(arena, CUSTOM_ROOT, "/4coder_default_bindings.cpp"); + char* build_cmd = fm_str(arena, "\"", build_script, "\" \"", default_custom_target, "\""); + + if (OS_WINDOWS) + build_cmd = fm_str(arena, "call ", build_cmd); + + if (flags.type == MODE_RELEASE) + build_cmd = fm_str(arena, build_cmd, " release"); + + if (flags.opts & VERBOSE) + printf("%s\n", build_cmd); + + systemf("%s", build_cmd); + + fm_popdir(dir); + + if (prev_error != 0) + return; + } + + // Setup prequesites for build + + List_String_Const_char includes = {}; + string_list_push(arena, &includes, SCchar(SRC_ROOT)); + string_list_push(arena, &includes, SCchar(CUSTOM_ROOT)); + string_list_push(arena, &includes, SCchar(fm_str(arena, FOREIGN_ROOT, "/freetype2"))); + + if (OS_MAC || OS_LINUX) + string_list_push(arena, &includes, SCchar("platform_unix")); + + List_String_Const_char defines = {}; + switch (flags.type) { + case MODE_DEBUG: + string_list_push(arena, &defines, SCchar("FRED_INTERNAL")); + break; + case MODE_RELEASE: + string_list_push(arena, &defines, SCchar("SHIP_MODE")); + break; + case MODE_RELEASE_DEBINFO: + break; + default: + InvalidPath; + } + + switch (flags.backend) { + case GLAPI_OPENGL: + string_list_push(arena, &defines, SCchar("WIN32_OPENGL")); + break; + case GLAPI_DX11: + string_list_push(arena, &defines, SCchar("WIN32_DX11")); + break; + default: + InvalidPath; + } + + // Build 4ed_app + { + List_String_Const_char files = {}; + string_list_push(arena, &files, SCchar(fm_str(arena, SRC_ROOT, "/4ed_app_target.cpp"))); + + List_String_Const_char exports = {}; + string_list_push(arena, &exports, SCchar("app_get_functions")); + + flags.opts = flags.type | (flags.opts & VERBOSE) | OPTS | SHARED_CODE; + + build(arena, "4ed_app" DLL, files, defines, exports, includes, flags); + + if (prev_error != 0) + return; + } + + // Build Platform Layer + { + List_String_Const_char files = {}; + if (OS_WINDOWS) { + string_list_push(arena, &files, SCchar(fm_str(arena, SRC_ROOT, "/platform_win32/win32_4ed.cpp"))); + } else if (OS_LINUX) { + string_list_push(arena, &files, SCchar(fm_str(arena, SRC_ROOT, "/platform_linux/linux_4ed.cpp"))); + } else if (OS_MAC) { + string_list_push(arena, &files, SCchar(fm_str(arena, SRC_ROOT, "/platform_mac/mac_4ed.mm"))); + } + + flags.opts = flags.type | (flags.opts & VERBOSE) | OPTS | LIBS | ICON; + + build(arena, "4ed", files, defines, {}, includes, flags); + + if (prev_error != 0) + return; + } + + // Copy distribution files into build dir + { + char *files[] = { + CUSTOM_ROOT, + fm_str(arena, NON_SRC_ROOT, "/dist_files"), + fm_str(arena, SRC_ROOT, "/ship_files"), + }; + + for (int i = 0; i < ArrayCount(files); i += 1) { + fm_copy_all(files[i], BUILD_ROOT); + } + } +} + +void usage(FILE* fd) { + fprintf(fd, R"(Usage: build [options] + +Options: + -m=, --mode= + Sets build mode + Available modes: + - debug + - release + - reldeb + Default: debug + + --gl-api= + Sets the graphics API to use + Available backends: + - OpenGL + - DX11 (Windows only) + Default: OpenGL + + -h, --help + Display this help text and exit + + -v, --verbose + Display build debug information like command currentely executing + )"); +} + +String_Const_char get_flag_value(String_Const_char flag) { + for (int i = 0; i < flag.size; ++i) { + if (flag.str[i] == '=') { + return SCchar(flag.str + i + 1, flag.size - i - 1); + } + } + return SCchar(""); +} + +BuildFlags parse_flags(int argc, const char** argv) { + // Default flags + BuildFlags flags = {}; + + for (int i = 1; i < argc; ++i) { + String_Const_char arg = SCchar((char*)argv[i]); + + if (arg == "-h" || arg == "--help") { + usage(stdout); + exit(0); + } else if (arg == "-v" || arg == "--verbose") { + flags.opts |= VERBOSE; + } else if (string_has_prefix(arg, "-m=") || string_has_prefix(arg, "--mode=")) { + String_Const_char param = get_flag_value(arg); + if (param == "release") { + flags.type = MODE_RELEASE; + } else if (param == "debug") { + flags.type = MODE_DEBUG; + } else if (param == "release_debinfo") { + flags.type = MODE_RELEASE_DEBINFO; + } else { + fprintf(stderr, "build: invalid mode '%.*s'\n", string_expand(param)); + usage(stderr); + exit(1); + } + } else if (string_has_prefix(arg, "--gl-api=")) { + String_Const_char param = get_flag_value(arg); + if (param == "DX11" && OS_WINDOWS) { + flags.backend = GLAPI_DX11; + } else if (param == "OpenGL") { + flags.backend = GLAPI_OPENGL; + } else { + fprintf(stderr, "build: invalid backend '%.*s'\n", string_expand(param)); + usage(stderr); + exit(1); + } + } else { + fprintf(stderr, "build: unrecognised option '%.*s'\n", string_expand(arg)); + usage(stderr); + exit(1); + } + } + + return flags; +} + +bool set_common_dirs(Arena* arena) { + char cwd[256]; + int cwd_size = fm_get_current_directory(cwd, sizeof(cwd)); + if (cwd_size >= sizeof(cwd)) + return false; + + // Get parent folder of cwd + for (int i = cwd_size - 1; i >= 0; --i) { + if (cwd[i] == (OS_WINDOWS ? '\\' : '/')) { + cwd[i] = '\0'; + break; + } + } + + BUILD_ROOT = fm_str(arena, cwd, "/build"); + SRC_ROOT = fm_str(arena, cwd, "/code"); + NON_SRC_ROOT = fm_str(arena, cwd, "/non-source"); + CUSTOM_ROOT = fm_str(arena, cwd, "/code/custom"); + FOREIGN_ROOT = fm_str(arena, cwd, "/non-source/foreign"); + + return true; +} + +int main(int argc, const char **argv){ + Arena arena = fm_init_system(DetailLevel_FileOperations); + + BuildFlags flags = parse_flags(argc, argv); + + if (!set_common_dirs(&arena)) + return 1; + + Temp_Memory temp = begin_temp(&arena); + dispatch_build(&arena, flags); + end_temp(temp); + + return error_state; +} + +// BOTTOM \ No newline at end of file diff --git a/code/bin/4ed_build.cpp b/code/bin/4ed_build.cpp deleted file mode 100644 index 72635e00b..000000000 --- a/code/bin/4ed_build.cpp +++ /dev/null @@ -1,611 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * ??.??.???? - * - * 4coder development build rule. - * - */ - -// TOP - -//#define FM_PRINT_COMMANDS - -#include "4coder_base_types.h" -#include "4coder_version.h" - -#include "4coder_base_types.cpp" -#include "4coder_malloc_allocator.cpp" - -#define FTECH_FILE_MOVING_IMPLEMENTATION -#include "4coder_file_moving.h" - - -// -// OS and compiler index -// - -typedef u32 Platform_Code; -enum{ - Platform_Windows, - Platform_Linux, - Platform_Mac, - // - Platform_COUNT, - Platform_None = Platform_COUNT, -}; - -char *platform_names[] = { - "win", - "linux", - "mac", -}; - -typedef u32 Compiler_Code; -enum{ - Compiler_CL, - Compiler_GCC, - Compiler_Clang, - // - Compiler_COUNT, - Compiler_None = Compiler_COUNT, -}; - -char *compiler_names[] = { - "cl", - "gcc", - "clang", -}; - -typedef u32 Arch_Code; -enum{ - Arch_X64, - Arch_X86, - Arch_arm64, - - // - Arch_COUNT, - Arch_None = Arch_COUNT, -}; - -char *arch_names[] = { - "x64", - "x86", - "arm64", -}; - -#if OS_WINDOWS -# define This_OS Platform_Windows -#elif OS_LINUX -# define This_OS Platform_Linux -#elif OS_MAC -# define This_OS Platform_Mac -#else -# error This platform is not enumerated. -#endif - -#if COMPILER_CL -# define This_Compiler Compiler_CL -#elif COMPILER_GCC -# define This_Compiler Compiler_GCC -#elif COMPILER_CLANG -# define This_Compiler Compiler_Clang -#else -# error This compilers is not enumerated. -#endif - -// -// Universal directories -// - -#define BUILD_DIR ".." SLASH "build" -#define SITE_DIR ".." SLASH "site" - -#define FOREIGN ".." SLASH "non-source" SLASH "foreign" - -char *includes[] = { "custom", FOREIGN SLASH "freetype2", 0, }; - -// -// Platform layer file tables -// - -char *windows_platform_layer[] = { "platform_win32/win32_4ed.cpp", 0 }; -char *linux_platform_layer[] = { "platform_linux/linux_4ed.cpp", 0 }; -char *mac_platform_layer[] = { "platform_mac/mac_4ed.mm", 0 }; - -char **platform_layers[Platform_COUNT] = { - windows_platform_layer, - linux_platform_layer , - mac_platform_layer , -}; - -char *windows_cl_platform_inc[] = { "platform_all", 0 }; -char *linux_gcc_platform_inc[] = { "platform_all", "platform_unix", 0 }; - -char *mac_clang_platform_inc[] = { "platform_all", "platform_unix", 0 }; - -char **platform_includes[Platform_COUNT][Compiler_COUNT] = { - {windows_cl_platform_inc, 0 , 0}, - {0 , linux_gcc_platform_inc, 0}, - {0 , 0 , mac_clang_platform_inc}, -}; - -char *default_custom_target = ".." SLASH "code" SLASH "custom" SLASH "4coder_default_bindings.cpp"; - -// NOTE(allen): Build flags - -enum{ - OPTS = 0x1, - LIBS = 0x2, - ICON = 0x4, - SHARED_CODE = 0x8, - DEBUG_INFO = 0x10, - OPTIMIZATION = 0x20, - SUPER = 0x40, - INTERNAL = 0x80, - SHIP = 0x100, - OPENGL = 0x200, - DX11 = 0x400, -}; - -internal char** -get_defines_from_flags(Arena *arena, u32 flags){ - char **result = 0; - if (HasFlag(flags, SHIP)){ - result = fm_list(arena, fm_list_one_item(arena, "SHIP_MODE"), result); - } - if (HasFlag(flags, INTERNAL)){ - result = fm_list(arena, fm_list_one_item(arena, "FRED_INTERNAL"), result); - } - if (HasFlag(flags, SUPER)){ - result = fm_list(arena, fm_list_one_item(arena, "FRED_SUPER"), result); - } - if (HasFlag(flags, OPENGL)) { - result = fm_list(arena, fm_list_one_item(arena, "WIN32_OPENGL"), result); - } else if (HasFlag(flags, DX11)) { - result = fm_list(arena, fm_list_one_item(arena, "WIN32_DX11"), result); - } - return(result); -} - -// -// build implementation: cl -// - -#if COMPILER_CL - -#define CL_OPTS \ -"-W4 -wd4310 -wd4100 -wd4201 -wd4505 -wd4996 " \ -"-wd4127 -wd4510 -wd4512 -wd4610 -wd4390 " \ -"-wd4611 -wd4189 -WX -GR- -EHa- -nologo -FC" - -#define CL_LIBS_COMMON \ -"user32.lib winmm.lib gdi32.lib comdlg32.lib userenv.lib " - -#if defined( WIN32_DX11 ) -#define CL_LIBS_BACKEND " d3d11.lib dxgi.lib d3dcompiler.lib" -#else -#define CL_LIBS_BACKEND " OpenGL32.lib" -#endif - -#define CL_LIBS_X64 CL_LIBS_COMMON FOREIGN "\\x64\\freetype.lib" CL_LIBS_BACKEND -#define CL_LIBS_X86 CL_LIBS_COMMON FOREIGN "\\x86\\freetype.lib" CL_LIBS_BACKEND - -#define CL_ICON "..\\non-source\\res\\icon.res" - -internal void -build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ - Temp_Dir temp = fm_pushdir(out_path); - - Build_Line line; - fm_init_build_line(&line); - - if (arch == Arch_X86){ - fm_add_to_line(line, "%s\\custom\\bin\\setup_cl_x86.bat &", code_path); - } - - fm_add_to_line(line, "cl"); - - if (flags & OPTS){ - fm_add_to_line(line, CL_OPTS); - } - - switch (arch){ - case Arch_X64: fm_add_to_line(line, "-DFTECH_64_BIT"); break; - case Arch_X86: fm_add_to_line(line, "-DFTECH_32_BIT"); break; - default: InvalidPath; - } - - fm_add_to_line(line, "-I%s", code_path); - if (inc_folders != 0){ - for (u32 i = 0; inc_folders[i] != 0; ++i){ - char *str = fm_str(arena, code_path, "/", inc_folders[i]); - fm_add_to_line(line, "-I%s", str); - } - } - - if (flags & LIBS){ - switch (arch){ - case Arch_X64: fm_add_to_line(line, CL_LIBS_X64); break; - case Arch_X86: fm_add_to_line(line, CL_LIBS_X86); break; - default: InvalidPath; - } - } - - if (flags & ICON){ - fm_add_to_line(line, CL_ICON); - } - - if (flags & DEBUG_INFO){ - fm_add_to_line(line, "-Zi"); - fm_add_to_line(line, "-DDO_CRAZY_EXPENSIVE_ASSERTS"); - } - - if (flags & OPTIMIZATION){ - fm_add_to_line(line, "-O2"); - } - - if (flags & SHARED_CODE){ - fm_add_to_line(line, "-LD"); - } - - if (defines != 0){ - for (u32 i = 0; defines[i] != 0; ++i){ - char *define_flag = fm_str(arena, "-D", defines[i]); - fm_add_to_line(line, "%s", define_flag); - } - } - - for (u32 i = 0; code_files[i]; ++i){ - fm_add_to_line(line, "\"%s\\%s\"", code_path, code_files[i]); - } - - fm_add_to_line(line, "-Fe%s", out_file); - - fm_add_to_line(line, "-link -INCREMENTAL:NO -RELEASE -PDBALTPATH:%%_PDB%%"); - switch (arch){ - case Arch_X64: fm_add_to_line(line, "-MACHINE:X64"); break; - case Arch_X86: fm_add_to_line(line, "-MACHINE:X86"); break; - default: InvalidPath; - } - - if (flags & DEBUG_INFO){ - fm_add_to_line(line, "-DEBUG"); - } - - if (flags & SHARED_CODE){ - Assert(exports != 0); - fm_add_to_line(line, "-OPT:REF"); - for (u32 i = 0; exports[i] != 0; ++i){ - char *str = fm_str(arena, "-EXPORT:", exports[i]); - fm_add_to_line(line, "%s", str); - } - } - else{ - fm_add_to_line(line, "-NODEFAULTLIB:library"); - } - - fm_finish_build_line(&line); - - //printf("%s\n", line.build_options); - systemf("%s", line.build_options); - fm_popdir(temp); - - fflush(stdout); -} - -// -// build implementation: gcc -// - -#elif COMPILER_GCC - -#if OS_LINUX - -# define GCC_OPTS \ -"-Wno-write-strings " \ -"-D_GNU_SOURCE -fPIC " \ -"-fno-threadsafe-statics -pthread " \ -"-Wno-unused-result " \ -"-std=c++11" - -# define GCC_LIBS_COMMON \ -"-lX11 -lpthread -lm -lrt " \ -"-lGL -ldl -lXfixes -lfreetype -lfontconfig" - -# define GCC_LIBS_X64 GCC_LIBS_COMMON -# define GCC_LIBS_X86 GCC_LIBS_COMMON - -#else -# error gcc options not set for this platform -#endif - -internal void -build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ - Build_Line line; - fm_init_build_line(&line); - - switch (arch){ - case Arch_X64: - fm_add_to_line(line, "-m64"); - fm_add_to_line(line, "-DFTECH_64_BIT"); break; - - case Arch_X86: - fm_add_to_line(line, "-m32"); - fm_add_to_line(line, "-DFTECH_32_BIT"); break; - - default: InvalidPath; - } - - if (flags & OPTS){ - fm_add_to_line(line, GCC_OPTS); - } - - fm_add_to_line(line, "-I%s", code_path); - if (inc_folders != 0){ - for (u32 i = 0; inc_folders[i] != 0; ++i){ - char *str = fm_str(arena, code_path, "/", inc_folders[i]); - fm_add_to_line(line, "-I%s", str); - } - } - - if (flags & DEBUG_INFO){ - fm_add_to_line(line, "-g -O0"); - } - - if (flags & OPTIMIZATION){ - fm_add_to_line(line, "-O3"); - } - - if (flags & SHARED_CODE){ - fm_add_to_line(line, "-shared"); - } - - if (defines != 0){ - for (u32 i = 0; defines[i]; ++i){ - char *define_flag = fm_str(arena, "-D", defines[i]); - fm_add_to_line(line, "%s", define_flag); - } - } - - fm_add_to_line(line, "-I\"%s\"", code_path); - for (u32 i = 0; code_files[i] != 0; ++i){ - fm_add_to_line(line, "\"%s/%s\"", code_path, code_files[i]); - } - - if (flags & LIBS){ - if (arch == Arch_X64){ - fm_add_to_line(line, GCC_LIBS_X64); - } - else if (arch == Arch_X86) - { - fm_add_to_line(line, GCC_LIBS_X86); - } - } - - fm_finish_build_line(&line); - - Temp_Dir temp = fm_pushdir(out_path); - systemf("g++ %s -o %s", line.build_options, out_file); - fm_popdir(temp); -} - -#elif COMPILER_CLANG - -#if OS_MAC - -# define CLANG_OPTS \ -"-Wno-write-strings -Wno-deprecated-declarations " \ -"-Wno-comment -Wno-switch -Wno-null-dereference " \ -"-Wno-tautological-compare -Wno-unused-result " \ -"-Wno-missing-declarations -Wno-nullability-completeness " \ -"-std=c++11 " - -# define CLANG_LIBS_COMMON \ -"-framework Cocoa -framework QuartzCore " \ -"-framework CoreServices " \ -"-framework OpenGL -framework IOKit -framework Metal -framework MetalKit " - -# define CLANG_LIBS_X64 CLANG_LIBS_COMMON \ -FOREIGN "/x64/libfreetype-mac.a" - -# define CLANG_LIBS_X86 CLANG_LIBS_COMMON \ -FOREIGN "/x86/libfreetype-mac.a" - -#else -# error clang options not set for this platform -#endif - -internal void -build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ - Build_Line line; - fm_init_build_line(&line); - - switch (arch){ - case Arch_X64: - fm_add_to_line(line, "-m64"); - fm_add_to_line(line, "-DFTECH_64_BIT"); break; - - case Arch_X86: - fm_add_to_line(line, "-m32"); - fm_add_to_line(line, "-DFTECH_32_BIT"); break; - - default: InvalidPath; - } - - if (flags & OPTS){ - fm_add_to_line(line, CLANG_OPTS); - } - - fm_add_to_line(line, "-I%s", code_path); - if (inc_folders != 0){ - for (u32 i = 0; inc_folders[i] != 0; ++i){ - char *str = fm_str(arena, code_path, "/", inc_folders[i]); - fm_add_to_line(line, "-I%s", str); - } - } - - if (flags & DEBUG_INFO){ - fm_add_to_line(line, "-g -O0"); - } - - if (flags & OPTIMIZATION){ - fm_add_to_line(line, "-O3"); - } - - if (flags & SHARED_CODE){ - fm_add_to_line(line, "-shared"); - } - - if (defines != 0){ - for (u32 i = 0; defines[i]; ++i){ - char *define_flag = fm_str(arena, "-D", defines[i]); - fm_add_to_line(line, "%s", define_flag); - } - } - - fm_add_to_line(line, "-I\"%s\"", code_path); - for (u32 i = 0; code_files[i] != 0; ++i){ - fm_add_to_line(line, "\"%s/%s\"", code_path, code_files[i]); - } - - if (flags & LIBS){ - if (arch == Arch_X64){ - fm_add_to_line(line, CLANG_LIBS_X64); - } - else if (arch == Arch_X86) - { - fm_add_to_line(line, CLANG_LIBS_X86); - } - } - - fm_finish_build_line(&line); - - Temp_Dir temp = fm_pushdir(out_path); - - // systemf("clang++ %s -E -o %s", line.build_options, "4ed.i"); - systemf("clang++ %s -o %s", line.build_options, out_file); - fm_popdir(temp); -} - -#else -# error build function not defined for this compiler -#endif - -internal void -build(Arena *arena, u32 flags, u32 arch, char *code_path, char *code_file, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){ - char **code_files = fm_list_one_item(arena, code_file); - build(arena, flags, arch, code_path, code_files, out_path, out_file, defines, exports, inc_folders); -} - -function void -dispatch_build(Arena *arena, u32 arch, char *cwd, u32 flags, char** dist_files, i32 dist_file_count){ - Temp_Dir temp = fm_pushdir(fm_str(arena, BUILD_DIR)); - - char *build_script_postfix = ""; - switch (This_OS){ - case Platform_Windows: - { - build_script_postfix = "-win"; - }break; - case Platform_Linux: - { - build_script_postfix = "-linux"; - }break; - case Platform_Mac: - { - build_script_postfix = "-mac"; - }break; - } - char *build_script = fm_str(arena, "custom/bin/buildsuper_", arch_names[arch], build_script_postfix, BAT); - - char *build_command = fm_str(arena, "\"", cwd, SLASH, build_script, "\" \"", default_custom_target, "\""); - if (This_OS == Platform_Windows){ - build_command = fm_str(arena, "call ", build_command); - } - - if (flags & OPTIMIZATION) { - build_command = fm_str(arena, build_command, " release"); - } - - systemf("%s", build_command); - - fm_popdir(temp); - fflush(stdout); - - { - char *file = fm_str(arena, "4ed_app_target.cpp"); - char **exports = fm_list_one_item(arena, "app_get_functions"); - build(arena, OPTS | SHARED_CODE | flags, arch, cwd, file, BUILD_DIR, "4ed_app" DLL, get_defines_from_flags(arena, flags), exports, includes); - } - - { - char **inc = (char**)fm_list(arena, includes, platform_includes[This_OS][This_Compiler]); - build(arena, OPTS | LIBS | ICON | flags, arch, cwd, platform_layers[This_OS], BUILD_DIR, "4ed", get_defines_from_flags(arena, flags), 0, inc); - } - - fflush(stdout); - - for (i32 j = 0; j < dist_file_count; j += 1){ - fm_copy_all(dist_files[j], BUILD_DIR); - } - - char *custom_src_dir = fm_str(arena, cwd, SLASH, "custom"); - char *custom_dst_dir = fm_str(arena, BUILD_DIR, SLASH, "custom"); - fm_make_folder_if_missing(arena, custom_dst_dir); - fm_copy_all(custom_src_dir, custom_dst_dir); -} - -int main(int argc, char **argv){ - Arena arena = fm_init_system(DetailLevel_FileOperations); - - char cwd[256]; - i32 n = fm_get_current_directory(cwd, sizeof(cwd)); - Assert(n < sizeof(cwd)); - - u32 flags = 0; - -#if ARCH_X86 - u32 arch = Arch_X86; -#elif ARCH_X64 - u32 arch = Arch_X64; -#elif ARCH_ARM64 - u32 arch = Arch_arm64; -#endif - -#if defined(DEV_BUILD) - flags |= DEBUG_INFO | INTERNAL; -#endif - -#if defined(OPT_BUILD) - flags |= OPTIMIZATION | SHIP; -#endif - -#if OS_WINDOWS - #if defined(WIN32_DX11) - flags |= DX11; - #else - flags |= OPENGL; - #endif -#endif - - // NOTE(allen): meta - char *dist_files[] = { - fm_str(&arena, "../non-source/dist_files"), - fm_str(&arena, "ship_files"), - }; - - printf("cwd: %s\n", cwd); - printf("BUILD: 4coder\n"); - printf(" arch: %s\n", arch_names[arch]); - printf(" build dir: %s\n", BUILD_DIR); - fflush(stdout); - - Temp_Memory temp = begin_temp(&arena); - dispatch_build(&arena, arch, cwd, flags, dist_files, ArrayCount(dist_files)); - end_temp(temp); - - return(error_state); -} - -// BOTTOM diff --git a/code/bin/build-linux.sh b/code/bin/build-linux.sh deleted file mode 100755 index bce5f56f3..000000000 --- a/code/bin/build-linux.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -# If any command errors, stop the script -set -e - -# Set up directories - -ME="$(readlink -f "$0")" -LOCATION="$(dirname "$ME")" -SRC_ROOT="$(dirname "$LOCATION")" -PROJECT_ROOT="$(dirname "$SRC_ROOT")" -if [ ! -d "$PROJECT_ROOT/build" ]; then -mkdir "$PROJECT_ROOT/build" -fi -BUILD_ROOT="$PROJECT_ROOT/build" -BIN_ROOT="$SRC_ROOT/bin" -CUSTOM_ROOT="$SRC_ROOT/custom" -CUSTOM_BIN="$CUSTOM_ROOT/bin" - -# Get the build mode -BUILD_MODE="$1" -if [ -z "$BUILD_MODE" ]; then - BUILD_MODE="-DDEV_BUILD" -fi - -WARNINGS="-Wno-write-strings -Wno-comment" - -FLAGS="-D_GNU_SOURCE -fPIC -fpermissive $BUILD_MODE" -INCLUDES="-I$SRC_ROOT -I$CUSTOM_ROOT" - -# Execute -g++ $WARNINGS $FLAGS $INCLUDES "$BIN_ROOT/4ed_build.cpp" -g -o "$BUILD_ROOT/build" -pushd "$SRC_ROOT" -"$BUILD_ROOT/build" -popd diff --git a/code/bin/build-mac.sh b/code/bin/build-mac.sh deleted file mode 100755 index adae80159..000000000 --- a/code/bin/build-mac.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -# If any command errors, stop the script -set -e - -# Set up directories -# NOTE(yuval): Replaced readlink with realpath which works for both macOS and Linux -ME="$(realpath "$0")" -LOCATION="$(dirname "$ME")" -SRC_ROOT="$(dirname "$LOCATION")" -PROJECT_ROOT="$(dirname "$SRC_ROOT")" -if [ ! -d "$PROJECT_ROOT/build" ]; then -mkdir "$PROJECT_ROOT/build" -fi -BUILD_ROOT="$PROJECT_ROOT/build" -BIN_ROOT="$SRC_ROOT/bin" -CUSTOM_ROOT="$SRC_ROOT/custom" -CUSTOM_BIN="$CUSTOM_ROOT/bin" - -# Get the build mode -BUILD_MODE="$1" -if [ -z "$BUILD_MODE" ]; then - BUILD_MODE="-DDEV_BUILD" -fi - -WARNINGS="-Wno-write-strings -Wno-comment -Wno-null-dereference -Wno-logical-op-parentheses -Wno-switch" - -FLAGS="-D_GNU_SOURCE -fPIC -fpermissive $BUILD_MODE" -INCLUDES="-I$SRC_ROOT -I$CUSTOM_ROOT" - -# Execute -clang++ $WARNINGS $FLAGS $INCLUDES "$BIN_ROOT/4ed_build.cpp" -g -o "$BUILD_ROOT/build" -pushd "$SRC_ROOT" -"$BUILD_ROOT/build" -popd diff --git a/code/bin/build.bat b/code/bin/build.bat deleted file mode 100644 index 6ddb30135..000000000 --- a/code/bin/build.bat +++ /dev/null @@ -1,52 +0,0 @@ -@echo off - -set location=%cd% -set me="%~dp0" - -REM 4cc\code\bin -cd %me% - -REM 4cc -cd ..\.. -set repo_root=%cd% -set src_root=%repo_root%\code -set build_root=%repo_root%\build -set bin_root=%repo_root%\code\bin -set custom_root=%repo_root%\code\custom -set custom_bin=%custom_root%\bin - -call %custom_bin%\setup_cl_x64.bat - -cd %location% - -set mode=%1 -set backend=%1 - -if "%1%" == "/DWIN32_OPENGL" ( - set mode=%2 -) else if "%1%" == "/DWIN32_DX11" ( - set mode=%2 -) else ( - set backend=%2 -) - -if "%backend%" == "" (set backend=/DWIN32_OPENGL) -if "%mode%" == "" (set mode=/DDEV_BUILD) - -set opts=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /wd4390 /wd4189 /WX -set opts=%opts% /GR- /EHa- /nologo /FC /Zi -set opts=%opts% /I%src_root% /I%custom_root% -set opts=%opts% %mode% %backend% - -set FirstError=0 - -if not exist "%build_root%" mkdir %build_root% -pushd %build_root% -call cl %opts% kernel32.lib %bin_root%\4ed_build.cpp /Febuild -if %ERRORLEVEL% neq 0 (set FirstError=1) -if %ERRORLEVEL% neq 0 (goto END) -popd - -%build_root%\build -:END -if %ERRORLEVEL% neq 0 (set FirstError=1) diff --git a/code/bin/build_optimized.bat b/code/bin/build_optimized.bat deleted file mode 100644 index feff93732..000000000 --- a/code/bin/build_optimized.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off - -call bin\build.bat /DOPT_BUILD %1 diff --git a/code/bin/detect_os.sh b/code/bin/detect_os.sh deleted file mode 100755 index 2160aa9e2..000000000 --- a/code/bin/detect_os.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -os="unknown" -if [[ "$OSTYPE" == "darwin"* ]]; then -echo "mac" -elif [[ "$OSTYPE" == "linux-gnu" ]]; then -echo "linux" -fi - diff --git a/code/custom/4coder_base_types.cpp b/code/custom/4coder_base_types.cpp index 8ca2e84d7..929f375db 100644 --- a/code/custom/4coder_base_types.cpp +++ b/code/custom/4coder_base_types.cpp @@ -4685,6 +4685,7 @@ string_match(String_Const_char a, String_Const_char b){ } return(result); } + function b32 string_match(String_Const_u8 a, String_Const_u8 b){ b32 result = false; @@ -5179,6 +5180,19 @@ string_mod_replace_character(String_Const_char str, char o, char n){ } return(str); } + +bool operator==(String_Const_char x, String_Const_char y) { + return string_match(x, y); +} + +bool operator==(String_Const_char x, const char* y) { + return string_match(x, SCchar((char*)y)); +} + +bool string_has_prefix(String_Const_char x, const char* prefix) { + return (string_find_first(x, SCchar((char*)prefix)) == 0); +} + function String_Const_u8 string_mod_replace_character(String_Const_u8 str, u8 o, u8 n){ for (u64 i = 0; i < str.size; i += 1){ From f3ac14ac43d174e9543d0fbafd3afec38543aa63 Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Thu, 21 May 2026 22:22:32 +0200 Subject: [PATCH 02/11] Update CI --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 64f7c45a5..07f435e06 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,16 +11,16 @@ jobs: include: - suffix: x64-win-dx11 os: windows-latest - build_cmd: bin\build.bat /DWIN32_DX11 + build_cmd: .\build.bat --gl-api=DX11 - suffix: x64-win-gl os: windows-latest - build_cmd: bin\build.bat /DWIN32_OPENGL + build_cmd: .\build.bat - suffix: x64-linux os: ubuntu-latest - build_cmd: sudo apt update -y && sudo apt install build-essential libx11-dev libxfixes-dev libglx-dev mesa-common-dev libasound2-dev libfreetype-dev libfontconfig-dev -y && ./bin/build-linux.sh + build_cmd: sudo apt update -y && sudo apt install build-essential libx11-dev libxfixes-dev libglx-dev mesa-common-dev libasound2-dev libfreetype-dev libfontconfig-dev -y && bash ./build.sh - suffix: x64-mac os: macos-15-intel - build_cmd: ./bin/build-mac.sh + build_cmd: bash ./build.sh # - suffix: arm64-mac # os: macos-latest # build_cmd: arch -arch x86_64 ./bin/build-mac.sh @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@v4 - uses: ilammy/msvc-dev-cmd@v1.4.1 # this is a no-op on Linux and macOS - name: Build 4cc-${{ matrix.suffix }} - run: cd code && ${{ matrix.build_cmd }} && cd .. + run: ${{ matrix.build_cmd }} - name: Generate 4cc Artifacts uses: actions/upload-artifact@v4.6.0 with: From 9d29bda73d3718701c1d000c02f81db9b944e32f Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Thu, 21 May 2026 22:30:04 +0200 Subject: [PATCH 03/11] Update README --- README.md | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 6f9cfd072..e7f979a03 100644 --- a/README.md +++ b/README.md @@ -7,19 +7,10 @@ > [!NOTE] > 4coder needs the MSVC compiler and windows SDK from the "Desktop development with C++" component. If you don’t have this already, you can download the installer [here](https://visualstudio.microsoft.com/downloads/). Make sure to at least click on "Desktop development with C++" and tick the boxes for MSVC and the Windows SDK. -1. Setup the MSVC toolchain in your environment, this can be done either with the `code/custom/bin/setup_cl_x64.bat` script or by using the development shell in windows terminal -2. Execute this command from the root of the project (the resulting executable will be under the `build` folder in the root of the repo) - -```batch -cd code && .\bin\build.bat -``` - -In addition to the parameter listed below, you can specify which backend to use by passing one of those parameters to the build scripts: -- `/DWIN32_OPENGL` (default) to use the OpenGL backend. -- `/DWIN32_DX11` to use the Direct3D 11 backend. +1. Execute this command from the root of the project (the resulting executable will be under the `build` folder in the root of the repo) -```batch -cd code && .\bin\build.bat /DWIN32_DX11 +```cmd +.\build.bat ``` ## Linux @@ -35,7 +26,7 @@ sudo apt install build-essential libx11-dev libxfixes-dev libglx-dev mesa-common 2. Execute this command from the root of the project (the resulting executable will be under the `build` folder in the root of the repo) ```sh -cd code && ./bin/build-linux.sh +./build.sh ``` ## Mac @@ -45,26 +36,24 @@ cd code && ./bin/build-linux.sh 1. Execute this command from the root of the project (the resulting executable will be under the `build` folder in the root of the repo) ```sh -cd code && ./bin/build-mac.sh +./build.sh +# For M1+ Macs +arch -arch x86_64 ./build.sh ``` -### Older Macs, 10.15.7 Catalina - -If you are using an older version of mac, such as 10.15.7 Catalina you need to install the realpath command: +## Build script parameter -1. `$ sudo port install coreutils` -2. macports names the `realpath` command `grealpath`, so make a symbolic link in order to use build-mac.sh: - `$ sudo ln -s /opt/local/bin/grealpath /opt/local/bin/realpath` +Check available options by running: -## Build script parameter +Windows: +```cmd +.\build.bat --help +``` -The build script accepts a parameter (mutually exclusive): -- `/DDEV_BUILD` (default value) : build without optimizations. - Produces debug symbols. - Defines: `FRED_INTERNAL`, `FRED_SUPER`, `DO_CRAZY_EXPENSIVE_ASSERTS` (on Windows) macros. -- `/DOPT_BUILD` (similar to `build_optimized` script): build with optimizations. - Doesn't produce debug symbols. - Defines `FRED_SUPER` macro. +Linux/MacOS: +```sh +./build.sh --help +``` ## API generators From 02e23001f0eeaac5546ca6ba1e3bf69b7f53aa41 Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Mon, 15 Jun 2026 17:49:34 +0200 Subject: [PATCH 04/11] Add support for Visual Studio 2026 --- code/custom/bin/setup_cl_generic.bat | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/custom/bin/setup_cl_generic.bat b/code/custom/bin/setup_cl_generic.bat index 151e64c2c..e266b24c5 100644 --- a/code/custom/bin/setup_cl_generic.bat +++ b/code/custom/bin/setup_cl_generic.bat @@ -35,3 +35,8 @@ IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcv SET VC_PATH=C:\Program Files\Microsoft Visual Studio\2022\Professional IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %1)) +SET VC_PATH=C:\Program Files\Microsoft Visual Studio\18\Community +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %1)) + +SET VC_PATH=C:\Program Files\Microsoft Visual Studio\18\Professional +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %1)) \ No newline at end of file From 51590ecc0d8cef90162d4bb42156f5ec76e12942 Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Mon, 15 Jun 2026 17:50:34 +0200 Subject: [PATCH 05/11] Update after review --- .github/workflows/build.yml | 2 +- README.md | 50 +++-- build.bat | 11 +- build.sh | 20 +- code/4ed_build.cpp | 342 ++++++++++++++++-------------- code/custom/4coder_base_types.cpp | 12 +- code/custom/bin/setup_cl_x86.bat | 3 + 7 files changed, 250 insertions(+), 190 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 07f435e06..3a60e06c6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: build_cmd: .\build.bat --gl-api=DX11 - suffix: x64-win-gl os: windows-latest - build_cmd: .\build.bat + build_cmd: .\build.bat --gl-api=OpenGL - suffix: x64-linux os: ubuntu-latest build_cmd: sudo apt update -y && sudo apt install build-essential libx11-dev libxfixes-dev libglx-dev mesa-common-dev libasound2-dev libfreetype-dev libfontconfig-dev -y && bash ./build.sh diff --git a/README.md b/README.md index e7f979a03..82e39a4dd 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,42 @@ # Building +## Build script parameter + +Check available options by running: + +``` +Usage: build [options] + +Options: + -m=, --mode= + Sets build mode + Available modes: + - debug + - release + Default: debug + + -gl= --gl-api= + Sets the graphics API to use + Available backends: + - OpenGL + - DX11 (Windows only) + Default: OpenGL + + -s, --symbols + Adds debug symbols. Already set by --mode=debug. + + -O, --optimizations + Adds optimizations. Already set by --mode=release. + + -h, --help + Display this help text and exit + + -v, --verbose + Display build debug information like command currentely executing + +``` + ## Windows > [!NOTE] @@ -41,20 +77,6 @@ sudo apt install build-essential libx11-dev libxfixes-dev libglx-dev mesa-common arch -arch x86_64 ./build.sh ``` -## Build script parameter - -Check available options by running: - -Windows: -```cmd -.\build.bat --help -``` - -Linux/MacOS: -```sh -./build.sh --help -``` - ## API generators 4coder uses several small programs to generate some headers and source files. Those do not run automatically, you must build them and run them when needed (which shouldn't really happen). diff --git a/build.bat b/build.bat index 14a6b63d6..31e3b92e3 100644 --- a/build.bat +++ b/build.bat @@ -1,8 +1,11 @@ @echo off +set prev_cwd=%cd% + rem Make sure we are at the root of the project cd /D "%~dp0" +set root=%cd% set src_root=%cd%\code set custom_root=%src_root%\custom set build_root=%cd%\build @@ -18,9 +21,11 @@ set opts=/nologo /FC /Zi /I%src_root% /I%custom_root% if not exist "%build_root%" mkdir %build_root% pushd %build_root% call cl %opts% %src_root%\4ed_build.cpp /Febuild -if %ERRORLEVEL% neq 0 exit /b popd -pushd %src_root% +if %ERRORLEVEL% neq 0 exit /b + %build_root%\build.exe %* -popd + +:END +cd /D "%prev_cwd%" \ No newline at end of file diff --git a/build.sh b/build.sh index 9724dfe8b..eac8df9d8 100644 --- a/build.sh +++ b/build.sh @@ -1,4 +1,15 @@ -#!/usr/bin/env bash +#!/bin/sh + +# '/bin/sh' is the most portable way to write a shellscript but doesn't +# support some features that bash does (e.g. using '[[' is not supported +# you can you '['). +# +# To be sure that the script is portable and fully POSIX # compliant use a +# tool like shellcheck to validate it. +# +# https://github.com/koalaman/shellcheck + +# shellcheck disable=SC2048,SC2086 set -e @@ -9,7 +20,8 @@ SRC_ROOT="$PWD/code" CUSTOM_ROOT="$SRC_ROOT/custom" BUILD_ROOT="$PWD/build" -if [[ -z "$CC" ]]; then +# c++ is the default toolchain's compiler installed on the machine +if [ -z "$CC" ]; then CC=c++ fi @@ -17,12 +29,10 @@ CFLAGS="-D_GNU_SOURCE -fPIC -fpermissive -Wno-write-strings -Wno-comment" CFLAGS="$CFLAGS -Wno-null-dereference -Wno-logical-op-parentheses -Wno-switch" CFLAGS="$CFLAGS -I$SRC_ROOT -I$CUSTOM_ROOT" -if [[ ! -d "$BUILD_ROOT" ]]; then +if [ ! -d "$BUILD_ROOT" ]; then mkdir -p "$BUILD_ROOT" fi eval "$CC $CFLAGS $SRC_ROOT/4ed_build.cpp -g -o $BUILD_ROOT/build" -pushd "$SRC_ROOT" "$BUILD_ROOT/build" $* -popd diff --git a/code/4ed_build.cpp b/code/4ed_build.cpp index d7df25329..048acffba 100644 --- a/code/4ed_build.cpp +++ b/code/4ed_build.cpp @@ -7,12 +7,18 @@ #include "4coder_base_types.cpp" #include "4coder_malloc_allocator.cpp" +//'prev_error' and 'error_state' come from "4coder_file_moving.h" and indicate +// an error happened with a file moving operation. #define FTECH_FILE_MOVING_IMPLEMENTATION #include "4coder_file_moving.h" +// Utilities + #define ForEachNode(NAME, LIST) \ for (auto* NAME = (LIST)->first; NAME != NULL; NAME = NAME->next) +#define smchi(X, Y) string_match_insensitive(X, Y) + // Constants static char* BUILD_ROOT; @@ -24,16 +30,13 @@ static char* FOREIGN_ROOT; // Build Options enum { - OPTS = bit_1, - LIBS = bit_2, - ICON = bit_3, - SHARED_CODE = bit_4, - DEBUG_INFO = bit_5, - OPTIMIZATION = bit_6, - SUPER = bit_7, - INTERNAL = bit_8, - SHIP = bit_9, - VERBOSE = bit_10, + LIBS = bit_1, + ICON = bit_2, + SHARED_CODE = bit_3, + DEBUG_INFO = bit_4, + OPTIMIZATION = bit_5, + SHIP = bit_6, + VERBOSE = bit_7, }; enum GLAPI { @@ -42,9 +45,8 @@ enum GLAPI { }; enum BuildMode { - MODE_DEBUG = DEBUG_INFO | INTERNAL, + MODE_DEBUG = DEBUG_INFO, MODE_RELEASE = OPTIMIZATION | SHIP, - MODE_RELEASE_DEBINFO = MODE_DEBUG | MODE_RELEASE, }; struct BuildFlags { @@ -71,68 +73,48 @@ void build( fm_add_to_line(line, "cl"); - if (flags.opts & OPTS){ - const char* opts[] = { - "-W4", // Enables all warnings - "-WX", // Raise warnings to errors - "-nologo", // Suppress copyright message - "-FC", // Use full pathnames in diagnostics - "-GR-", // Disable Runtime Type informations - "-EHa-", // Disable C++ EH (w/ SEH exceptions) - "-wd4310", // Disable "cast truncates constant value" - "-wd4100", // Disable "'identifier' : unreferenced formal parameter" - "-wd4201", // Disable "nonstandard extension used : nameless struct/union " - "-wd4505", // Disable "'function' : unreferenced local function has been removed" - "-wd4996", // Disable "deprecation warnings" - "-wd4127", // Disable "conditional expression is constant" - "-wd4510", // Disable "'class': default constructor was implicitly defined as deleted" - "-wd4512", // Disable "'class' : assignment operator could not be generated " - "-wd4610", // Disable "object 'class' can never be instantiated - user-defined constructor required" - "-wd4390", // Disable "';' : empty controlled statement found; is this the intent?" - "-wd4611", // Disable "interaction between 'function' and C++ object destruction is non-portable" - "-wd4189", // Disable "'identifier' : local variable is initialized but not referenced" - }; - - for (int i = 0; i < ArrayCount(opts); ++i) - fm_add_to_line(line, "%s", opts[i]); + fm_add_to_line(line, "-Fe%s", out_file); + + const char* opts[] = { + "-W4", // Enables all warnings + "-WX", // Raise warnings to errors + "-nologo", // Suppress copyright message + "-FC", // Use full pathnames in diagnostics + "-GR-", // Disable Runtime Type informations + "-EHa-", // Disable C++ EH (w/ SEH exceptions) + "-wd4310", // Disable "cast truncates constant value" + "-wd4100", // Disable "'identifier' : unreferenced formal parameter" + "-wd4201", // Disable "nonstandard extension used : nameless struct/union " + "-wd4505", // Disable "'function' : unreferenced local function has been removed" + "-wd4996", // Disable "deprecation warnings" + "-wd4127", // Disable "conditional expression is constant" + "-wd4510", // Disable "'class': default constructor was implicitly defined as deleted" + "-wd4512", // Disable "'class' : assignment operator could not be generated " + "-wd4610", // Disable "object 'class' can never be instantiated - user-defined constructor required" + "-wd4390", // Disable "';' : empty controlled statement found; is this the intent?" + "-wd4611", // Disable "interaction between 'function' and C++ object destruction is non-portable" + "-wd4189", // Disable "'identifier' : local variable is initialized but not referenced" + }; + + for (int i = 0; i < ArrayCount(opts); ++i) { + fm_add_to_line(line, "%s", opts[i]); } - if (flags.opts & LIBS) { - fm_add_to_line(line, "%s", "user32.lib winmm.lib gdi32.lib comdlg32.lib userenv.lib"); - - if (ARCH_X64) { - fm_add_to_line(line, "%s", fm_str(arena, FOREIGN_ROOT, "\\x64\\freetype.lib")); - } else if (ARCH_X86) { - fm_add_to_line(line, "%s", fm_str(arena, FOREIGN_ROOT, "\\x86\\freetype.lib")); - } else { - InvalidPath; - } - - switch (flags.backend) { - case GLAPI_OPENGL: - fm_add_to_line(line, "OpenGL32.lib"); - break; - case GLAPI_DX11: - fm_add_to_line(line, "d3d11.lib dxgi.lib d3dcompiler.lib"); - break; - default: - InvalidPath; - } + if (flags.type == MODE_DEBUG && !(flags.opts & OPTIMIZATION)) { + fm_add_to_line(line, "-Od"); } - - if (flags.opts & ICON) - fm_add_to_line(line, "..\\non-source\\res\\icon.res"); if (flags.opts & DEBUG_INFO) { fm_add_to_line(line, "-Zi"); - fm_add_to_line(line, "-DDO_CRAZY_EXPENSIVE_ASSERTS"); } - - if (flags.opts & OPTIMIZATION) + + if (flags.opts & OPTIMIZATION) { fm_add_to_line(line, "-O2"); + } - if (flags.opts & SHARED_CODE) + if (flags.opts & SHARED_CODE) { fm_add_to_line(line, "-LD"); + } ForEachNode(iter, &includes) { fm_add_to_line(line, "-I%.*s", string_expand(iter->string)); @@ -145,8 +127,35 @@ void build( ForEachNode(iter, &files) { fm_add_to_line(line, "\"%.*s\"", string_expand(iter->string)); } - - fm_add_to_line(line, "-Fe%s", out_file); + + if (flags.opts & ICON) { + fm_add_to_line(line, "..\\non-source\\res\\icon.res"); + } + + if (flags.opts & LIBS) { + fm_add_to_line(line, "%s", "user32.lib winmm.lib gdi32.lib comdlg32.lib userenv.lib"); + + if (ARCH_X64) { + fm_add_to_line(line, "%s", fm_str(arena, FOREIGN_ROOT, "\\x64\\freetype.lib")); + } else if (ARCH_X86) { + fm_add_to_line(line, "%s", fm_str(arena, FOREIGN_ROOT, "\\x86\\freetype.lib")); + } else { + InvalidPath; + } + + switch (flags.backend) { + case GLAPI_OPENGL: { + fm_add_to_line(line, "OpenGL32.lib"); + } break; + case GLAPI_DX11: { + fm_add_to_line(line, "d3d11.lib dxgi.lib d3dcompiler.lib"); + } break; + default: { + InvalidPath; + }break; + } + } + fm_add_to_line(line, "-link -INCREMENTAL:NO -RELEASE -PDBALTPATH:%%_PDB%%"); @@ -198,23 +207,28 @@ void build( fm_init_build_line(&line); fm_add_to_line(line, "g++"); + + fm_add_to_line(line, "-o %s", out_file); - if (flags.opts & OPTS) { - const char* opts[] = { - "-D_GNU_SOURCE", // Enable GNU extentions - "-fPIC", // Enable Position Independent Code - "-fno-threadsafe-statics -pthread", // Don't use C++ thread safety routines - "-Wno-write-strings", // Disable "warning: deprecated conversion from string constant to 'char*'" - "-Wno-unused-result", // Disable "warning: ignoring return value of 'function_name'" - "-std=c++11", - }; + const char* opts[] = { + "-D_GNU_SOURCE", // Enable GNU extentions + "-fPIC", // Enable Position Independent Code + "-fno-threadsafe-statics -pthread", // Don't use C++ thread safety routines + "-Wno-write-strings", // Disable "warning: deprecated conversion from string constant to 'char*'" + "-Wno-unused-result", // Disable "warning: ignoring return value of 'function_name'" + "-std=c++11", + }; - for (int i = 0; i < ArrayCount(opts); ++i) - fm_add_to_line(line, "%s", opts[i]); + for (int i = 0; i < ArrayCount(opts); ++i) { + fm_add_to_line(line, "%s", opts[i]); } - + + if (flags.type == MODE_DEBUG && !(flags.opts & OPTIMIZATION)) { + fm_add_to_line(line, "-O0"); + } + if (flags.opts & DEBUG_INFO) { - fm_add_to_line(line, "-g -O0"); + fm_add_to_line(line, "-g"); } if (flags.opts & OPTIMIZATION) { @@ -241,8 +255,6 @@ void build( fm_add_to_line(line, "-lX11 -lpthread -lm -lrt -lGL -ldl -lXfixes -lfreetype -lfontconfig"); } - fm_add_to_line(line, "-o %s", out_file); - fm_finish_build_line(&line); if (flags.opts & VERBOSE) { @@ -270,33 +282,38 @@ void build( fm_init_build_line(&line); fm_add_to_line(line, "clang++"); + + fm_add_to_line(line, "-o %s", out_file); - if (flags.opts & OPTS){ - const char* opts[] = { - "-Wno-write-strings", // Disable "warning: deprecated conversion from string constant to 'char*'" - "-Wno-deprecated-declarations", // Disable deprecation warnings - "-Wno-switch", // Disable "enumeration value B not handled in switch" - "-Wno-null-dereference", // Disable "warning: binding dereferenced null pointer to reference has undefined behavior" - "-Wno-unused-result", // Disable "warning: ignoring return value of 'function_name'" - "-Wno-missing-declarations", // Disable "warning: declaration does not declare anything" - "-Wno-nullability-completeness", // Disable "warning: pointer is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)" - "-Wno-tautological-compare", - "-std=c++11 ", - }; + const char* opts[] = { + "-Wno-write-strings", // Disable "warning: deprecated conversion from string constant to 'char*'" + "-Wno-deprecated-declarations", // Disable deprecation warnings + "-Wno-switch", // Disable "enumeration value B not handled in switch" + "-Wno-null-dereference", // Disable "warning: binding dereferenced null pointer to reference has undefined behavior" + "-Wno-unused-result", // Disable "warning: ignoring return value of 'function_name'" + "-Wno-missing-declarations", // Disable "warning: declaration does not declare anything" + "-Wno-nullability-completeness", // Disable "warning: pointer is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)" + "-Wno-tautological-compare", + "-std=c++11 ", + }; - for (int i = 0; i < ArrayCount(opts); ++i) - fm_add_to_line(line, "%s", opts[i]); + for (int i = 0; i < ArrayCount(opts); ++i) { + fm_add_to_line(line, "%s", opts[i]); + } + + if (flags.type == MODE_DEBUG && !(flags.opts & OPTIMIZATION)) { + fm_add_to_line(line, "-O0"); } - if (flags.opts & DEBUG_INFO){ - fm_add_to_line(line, "-g -O0"); + if (flags.opts & DEBUG_INFO) { + fm_add_to_line(line, "-g"); } - if (flags.opts & OPTIMIZATION){ + if (flags.opts & OPTIMIZATION) { fm_add_to_line(line, "-O3"); } - if (flags.opts & SHARED_CODE){ + if (flags.opts & SHARED_CODE) { fm_add_to_line(line, "-shared"); } @@ -326,8 +343,6 @@ void build( InvalidPath; } } - - fm_add_to_line(line, "-o %s", out_file); fm_finish_build_line(&line); @@ -353,21 +368,25 @@ dispatch_build(Arena* arena, BuildFlags flags) { char* default_custom_target = fm_str(arena, CUSTOM_ROOT, "/4coder_default_bindings.cpp"); char* build_cmd = fm_str(arena, "\"", build_script, "\" \"", default_custom_target, "\""); - if (OS_WINDOWS) + if (OS_WINDOWS) { build_cmd = fm_str(arena, "call ", build_cmd); + } - if (flags.type == MODE_RELEASE) + if (flags.type == MODE_RELEASE) { build_cmd = fm_str(arena, build_cmd, " release"); + } - if (flags.opts & VERBOSE) + if (flags.opts & VERBOSE) { printf("%s\n", build_cmd); + } systemf("%s", build_cmd); fm_popdir(dir); - if (prev_error != 0) + if (prev_error != 0) { return; + } } // Setup prequesites for build @@ -377,32 +396,35 @@ dispatch_build(Arena* arena, BuildFlags flags) { string_list_push(arena, &includes, SCchar(CUSTOM_ROOT)); string_list_push(arena, &includes, SCchar(fm_str(arena, FOREIGN_ROOT, "/freetype2"))); - if (OS_MAC || OS_LINUX) + if (OS_MAC || OS_LINUX) { string_list_push(arena, &includes, SCchar("platform_unix")); + } List_String_Const_char defines = {}; switch (flags.type) { - case MODE_DEBUG: - string_list_push(arena, &defines, SCchar("FRED_INTERNAL")); - break; - case MODE_RELEASE: - string_list_push(arena, &defines, SCchar("SHIP_MODE")); - break; - case MODE_RELEASE_DEBINFO: - break; - default: - InvalidPath; + case MODE_DEBUG: { + string_list_push(arena, &defines, SCchar("FRED_INTERNAL")); + string_list_push(arena, &defines, SCchar("DO_CRAZY_EXPENSIVE_ASSERTS")); + } break; + case MODE_RELEASE: { + string_list_push(arena, &defines, SCchar("SHIP_MODE")); + string_list_push(arena, &defines, SCchar("NDEBUG")); + } break; + default: { + InvalidPath; + } break; } switch (flags.backend) { - case GLAPI_OPENGL: - string_list_push(arena, &defines, SCchar("WIN32_OPENGL")); - break; - case GLAPI_DX11: - string_list_push(arena, &defines, SCchar("WIN32_DX11")); - break; - default: - InvalidPath; + case GLAPI_OPENGL: { + string_list_push(arena, &defines, SCchar("WIN32_OPENGL")); + } break; + case GLAPI_DX11: { + string_list_push(arena, &defines, SCchar("WIN32_DX11")); + } break; + default: { + InvalidPath; + } break; } // Build 4ed_app @@ -413,12 +435,13 @@ dispatch_build(Arena* arena, BuildFlags flags) { List_String_Const_char exports = {}; string_list_push(arena, &exports, SCchar("app_get_functions")); - flags.opts = flags.type | (flags.opts & VERBOSE) | OPTS | SHARED_CODE; - - build(arena, "4ed_app" DLL, files, defines, exports, includes, flags); + BuildFlags opts = flags; + opts.opts = flags.type | flags.opts | SHARED_CODE; + build(arena, "4ed_app" DLL, files, defines, exports, includes, opts); - if (prev_error != 0) + if (prev_error != 0) { return; + } } // Build Platform Layer @@ -432,18 +455,18 @@ dispatch_build(Arena* arena, BuildFlags flags) { string_list_push(arena, &files, SCchar(fm_str(arena, SRC_ROOT, "/platform_mac/mac_4ed.mm"))); } - flags.opts = flags.type | (flags.opts & VERBOSE) | OPTS | LIBS | ICON; + BuildFlags opts = flags; + opts.opts = flags.type | flags.opts | LIBS | ICON; + build(arena, "4ed", files, defines, {}, includes, opts); - build(arena, "4ed", files, defines, {}, includes, flags); - - if (prev_error != 0) + if (prev_error != 0) { return; + } } // Copy distribution files into build dir { char *files[] = { - CUSTOM_ROOT, fm_str(arena, NON_SRC_ROOT, "/dist_files"), fm_str(arena, SRC_ROOT, "/ship_files"), }; @@ -451,6 +474,10 @@ dispatch_build(Arena* arena, BuildFlags flags) { for (int i = 0; i < ArrayCount(files); i += 1) { fm_copy_all(files[i], BUILD_ROOT); } + + char* custom_dst = fm_str(arena, BUILD_ROOT, "/custom"); + fm_make_folder_if_missing(arena, custom_dst); + fm_copy_all(CUSTOM_ROOT, custom_dst); } } @@ -463,16 +490,21 @@ void usage(FILE* fd) { Available modes: - debug - release - - reldeb Default: debug - --gl-api= + -gl= --gl-api= Sets the graphics API to use Available backends: - OpenGL - DX11 (Windows only) Default: OpenGL + -s, --symbols + Adds debug symbols. Already set by --mode=debug. + + -O, --optimizations + Adds optimizations. Already set by --mode=release. + -h, --help Display this help text and exit @@ -497,29 +529,32 @@ BuildFlags parse_flags(int argc, const char** argv) { for (int i = 1; i < argc; ++i) { String_Const_char arg = SCchar((char*)argv[i]); - if (arg == "-h" || arg == "--help") { + if (smchi(arg, SCchar("-h")) || smchi(arg, SCchar("--help"))) { usage(stdout); exit(0); - } else if (arg == "-v" || arg == "--verbose") { + } else if (smchi(arg, SCchar("-v")) || smchi(arg, SCchar("--verbose"))) { flags.opts |= VERBOSE; - } else if (string_has_prefix(arg, "-m=") || string_has_prefix(arg, "--mode=")) { + } else if (smchi(arg, SCchar("-s")) || smchi(arg, SCchar("--symbols"))) { + flags.opts |= DEBUG_INFO; + } else if (smchi(arg, SCchar("-O")) || smchi(arg, SCchar("--optimiziations"))) { + flags.opts |= OPTIMIZATION; + } else if (string_has_prefix(arg, SCchar("-m=")) || string_has_prefix(arg, SCchar("--mode="))) { String_Const_char param = get_flag_value(arg); - if (param == "release") { + if (smchi(param, SCchar("release"))) { flags.type = MODE_RELEASE; - } else if (param == "debug") { + } else if (smchi(param, SCchar("debug"))) { flags.type = MODE_DEBUG; - } else if (param == "release_debinfo") { - flags.type = MODE_RELEASE_DEBINFO; } else { fprintf(stderr, "build: invalid mode '%.*s'\n", string_expand(param)); usage(stderr); exit(1); } - } else if (string_has_prefix(arg, "--gl-api=")) { + } else if (string_has_prefix(arg, SCchar("--gl-api=")) || string_has_prefix(arg, SCchar("-gl="))) { String_Const_char param = get_flag_value(arg); - if (param == "DX11" && OS_WINDOWS) { + + if (smchi(param, SCchar("DX11")) && OS_WINDOWS) { flags.backend = GLAPI_DX11; - } else if (param == "OpenGL") { + } else if (smchi(param, SCchar("OpenGL"))) { flags.backend = GLAPI_OPENGL; } else { fprintf(stderr, "build: invalid backend '%.*s'\n", string_expand(param)); @@ -539,15 +574,9 @@ BuildFlags parse_flags(int argc, const char** argv) { bool set_common_dirs(Arena* arena) { char cwd[256]; int cwd_size = fm_get_current_directory(cwd, sizeof(cwd)); - if (cwd_size >= sizeof(cwd)) + if (cwd_size >= sizeof(cwd)) { + fprintf(stderr, "CWD length exceed %zu characters. Aborting.", sizeof(cwd)); return false; - - // Get parent folder of cwd - for (int i = cwd_size - 1; i >= 0; --i) { - if (cwd[i] == (OS_WINDOWS ? '\\' : '/')) { - cwd[i] = '\0'; - break; - } } BUILD_ROOT = fm_str(arena, cwd, "/build"); @@ -561,15 +590,14 @@ bool set_common_dirs(Arena* arena) { int main(int argc, const char **argv){ Arena arena = fm_init_system(DetailLevel_FileOperations); - + BuildFlags flags = parse_flags(argc, argv); - if (!set_common_dirs(&arena)) + if (!set_common_dirs(&arena)) { return 1; + } - Temp_Memory temp = begin_temp(&arena); dispatch_build(&arena, flags); - end_temp(temp); return error_state; } diff --git a/code/custom/4coder_base_types.cpp b/code/custom/4coder_base_types.cpp index 929f375db..710dc0a81 100644 --- a/code/custom/4coder_base_types.cpp +++ b/code/custom/4coder_base_types.cpp @@ -5181,16 +5181,8 @@ string_mod_replace_character(String_Const_char str, char o, char n){ return(str); } -bool operator==(String_Const_char x, String_Const_char y) { - return string_match(x, y); -} - -bool operator==(String_Const_char x, const char* y) { - return string_match(x, SCchar((char*)y)); -} - -bool string_has_prefix(String_Const_char x, const char* prefix) { - return (string_find_first(x, SCchar((char*)prefix)) == 0); +bool string_has_prefix(String_Const_char s, String_Const_char prefix) { + return (string_match(string_prefix(s, prefix.size), prefix)); } function String_Const_u8 diff --git a/code/custom/bin/setup_cl_x86.bat b/code/custom/bin/setup_cl_x86.bat index 3266985f3..d1102d45e 100644 --- a/code/custom/bin/setup_cl_x86.bat +++ b/code/custom/bin/setup_cl_x86.bat @@ -1,5 +1,8 @@ @echo off +where /q cl +IF %ERRORLEVEL% == 0 (EXIT /b) + SET SCRIPTS_PATH=%~dp0 "%SCRIPTS_PATH%\setup_cl_generic.bat" amd64_x86 From beba30ee40bb578c73c760b9619bcf7f0124c117 Mon Sep 17 00:00:00 2001 From: Jack Punter Date: Mon, 22 Jun 2026 14:44:17 +0100 Subject: [PATCH 06/11] Add executable flag to build.sh --- .github/workflows/build.yml | 4 ++-- .vscode/c_cpp_properties.json | 20 ++++++++++++++++++++ .vscode/launch.json | 33 +++++++++++++++++++++++++++++++++ .vscode/settings.json | 9 +++++++++ build.sh | 0 5 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json mode change 100644 => 100755 build.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3a60e06c6..a48670180 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,10 +17,10 @@ jobs: build_cmd: .\build.bat --gl-api=OpenGL - suffix: x64-linux os: ubuntu-latest - build_cmd: sudo apt update -y && sudo apt install build-essential libx11-dev libxfixes-dev libglx-dev mesa-common-dev libasound2-dev libfreetype-dev libfontconfig-dev -y && bash ./build.sh + build_cmd: sudo apt update -y && sudo apt install build-essential libx11-dev libxfixes-dev libglx-dev mesa-common-dev libasound2-dev libfreetype-dev libfontconfig-dev -y && ./build.sh - suffix: x64-mac os: macos-15-intel - build_cmd: bash ./build.sh + build_cmd: ./build.sh # - suffix: arm64-mac # os: macos-latest # build_cmd: arch -arch x86_64 ./bin/build-mac.sh diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 000000000..3e8a6d5e4 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,20 @@ +{ + "configurations": [ + { + "browse": { + "databaseFilename": "${workspaceFolder}/.vscode/browse.vc.db", + "limitSymbolsToIncludedHeaders": false + }, + "includePath": [ + "/opt/ros/kilted/include/**", + "/usr/include/**" + ], + "name": "ros2", + "intelliSenseMode": "gcc-x64", + "compilerPath": "/usr/bin/gcc", + "cStandard": "gnu11", + "cppStandard": "c++17" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..1a91318ea --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,33 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Launch", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/4ed", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/build/", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ] + } + + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..db704f276 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "ROS2.distro": "kilted", + "python.autoComplete.extraPaths": [ + "/opt/ros/kilted/lib/python3.12/site-packages" + ], + "python.analysis.extraPaths": [ + "/opt/ros/kilted/lib/python3.12/site-packages" + ] +} \ No newline at end of file diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 From 80cb952622ff27c9b44e18a5283f31fdd2c8ec63 Mon Sep 17 00:00:00 2001 From: Jack Punter Date: Mon, 22 Jun 2026 14:50:22 +0100 Subject: [PATCH 07/11] Remove the .vscode folder (my bad) --- .vscode/c_cpp_properties.json | 20 -------------------- .vscode/launch.json | 33 --------------------------------- .vscode/settings.json | 9 --------- 3 files changed, 62 deletions(-) delete mode 100644 .vscode/c_cpp_properties.json delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index 3e8a6d5e4..000000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "configurations": [ - { - "browse": { - "databaseFilename": "${workspaceFolder}/.vscode/browse.vc.db", - "limitSymbolsToIncludedHeaders": false - }, - "includePath": [ - "/opt/ros/kilted/include/**", - "/usr/include/**" - ], - "name": "ros2", - "intelliSenseMode": "gcc-x64", - "compilerPath": "/usr/bin/gcc", - "cStandard": "gnu11", - "cppStandard": "c++17" - } - ], - "version": 4 -} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 1a91318ea..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "(gdb) Launch", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/build/4ed", - "args": [], - "stopAtEntry": false, - "cwd": "${workspaceFolder}/build/", - "environment": [], - "externalConsole": false, - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - }, - { - "description": "Set Disassembly Flavor to Intel", - "text": "-gdb-set disassembly-flavor intel", - "ignoreFailures": true - } - ] - } - - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index db704f276..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ROS2.distro": "kilted", - "python.autoComplete.extraPaths": [ - "/opt/ros/kilted/lib/python3.12/site-packages" - ], - "python.analysis.extraPaths": [ - "/opt/ros/kilted/lib/python3.12/site-packages" - ] -} \ No newline at end of file From ef417b73a960683abff5ea7b6289b6d5cad7535f Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Wed, 24 Jun 2026 14:42:07 +0200 Subject: [PATCH 08/11] Fix build.bat --- build.bat | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/build.bat b/build.bat index 31e3b92e3..2f05fd19c 100644 --- a/build.bat +++ b/build.bat @@ -5,16 +5,12 @@ set prev_cwd=%cd% rem Make sure we are at the root of the project cd /D "%~dp0" -set root=%cd% set src_root=%cd%\code set custom_root=%src_root%\custom set build_root=%cd%\build -if "%PROCESSOR_ARCHITECTURE%" == "AMD64" ( - call %custom_root%\bin\setup_cl_x64.bat -) else ( - call %custom_root%\bin\setup_cl_x86.bat -) +rem If the user want's 32 bits they need to setup MSVC before calling the script. +call %custom_root%\bin\setup_cl_x64.bat set opts=/nologo /FC /Zi /I%src_root% /I%custom_root% @@ -23,7 +19,7 @@ pushd %build_root% call cl %opts% %src_root%\4ed_build.cpp /Febuild popd -if %ERRORLEVEL% neq 0 exit /b +if %ERRORLEVEL% neq 0 goto END %build_root%\build.exe %* From b7829de4ac2b0278905c759b6c49b45ee0d1dc40 Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Wed, 24 Jun 2026 14:42:33 +0200 Subject: [PATCH 09/11] Remove DO_CRAZY_EXPENSIVE_ASSERTS --- code/4ed_build.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/code/4ed_build.cpp b/code/4ed_build.cpp index 048acffba..ff84d131f 100644 --- a/code/4ed_build.cpp +++ b/code/4ed_build.cpp @@ -404,7 +404,6 @@ dispatch_build(Arena* arena, BuildFlags flags) { switch (flags.type) { case MODE_DEBUG: { string_list_push(arena, &defines, SCchar("FRED_INTERNAL")); - string_list_push(arena, &defines, SCchar("DO_CRAZY_EXPENSIVE_ASSERTS")); } break; case MODE_RELEASE: { string_list_push(arena, &defines, SCchar("SHIP_MODE")); From 6d0e23ac24e48129349a441221a61739be9f92dd Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Wed, 24 Jun 2026 14:42:51 +0200 Subject: [PATCH 10/11] Use -o for optimiziations --- README.md | 4 +--- code/4ed_build.cpp | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 82e39a4dd..3884dcc65 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ ## Build script parameter -Check available options by running: - ``` Usage: build [options] @@ -27,7 +25,7 @@ Options: -s, --symbols Adds debug symbols. Already set by --mode=debug. - -O, --optimizations + -o, --optimizations Adds optimizations. Already set by --mode=release. -h, --help diff --git a/code/4ed_build.cpp b/code/4ed_build.cpp index ff84d131f..5cdcfe2d4 100644 --- a/code/4ed_build.cpp +++ b/code/4ed_build.cpp @@ -501,7 +501,7 @@ void usage(FILE* fd) { -s, --symbols Adds debug symbols. Already set by --mode=debug. - -O, --optimizations + -o, --optimizations Adds optimizations. Already set by --mode=release. -h, --help @@ -535,7 +535,7 @@ BuildFlags parse_flags(int argc, const char** argv) { flags.opts |= VERBOSE; } else if (smchi(arg, SCchar("-s")) || smchi(arg, SCchar("--symbols"))) { flags.opts |= DEBUG_INFO; - } else if (smchi(arg, SCchar("-O")) || smchi(arg, SCchar("--optimiziations"))) { + } else if (smchi(arg, SCchar("-o")) || smchi(arg, SCchar("--optimiziations"))) { flags.opts |= OPTIMIZATION; } else if (string_has_prefix(arg, SCchar("-m=")) || string_has_prefix(arg, SCchar("--mode="))) { String_Const_char param = get_flag_value(arg); From 5311492c9857215acd2ca82b826c4a94a759dab4 Mon Sep 17 00:00:00 2001 From: Luca Saccarola Date: Thu, 25 Jun 2026 13:14:26 +0200 Subject: [PATCH 11/11] Define WIN32_* backend only on windows --- code/4ed_build.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/code/4ed_build.cpp b/code/4ed_build.cpp index 5cdcfe2d4..b732981f0 100644 --- a/code/4ed_build.cpp +++ b/code/4ed_build.cpp @@ -414,16 +414,18 @@ dispatch_build(Arena* arena, BuildFlags flags) { } break; } - switch (flags.backend) { - case GLAPI_OPENGL: { - string_list_push(arena, &defines, SCchar("WIN32_OPENGL")); - } break; - case GLAPI_DX11: { - string_list_push(arena, &defines, SCchar("WIN32_DX11")); - } break; - default: { - InvalidPath; - } break; + if (OS_WINDOWS) { + switch (flags.backend) { + case GLAPI_OPENGL: { + string_list_push(arena, &defines, SCchar("WIN32_OPENGL")); + } break; + case GLAPI_DX11: { + string_list_push(arena, &defines, SCchar("WIN32_DX11")); + } break; + default: { + InvalidPath; + } break; + } } // Build 4ed_app