Revert "Death to C++"

This reverts commit 066ac22605.
This commit is contained in:
2026-03-11 19:15:36 -04:00
parent 066ac22605
commit 13f856cfbc
80 changed files with 39269 additions and 5672 deletions

274
build.c
View File

@@ -6,6 +6,36 @@
#define NOB_IMPLEMENTATION
#include "vendor/nob/nob.h"
////////////////////////////////
// lunasvg/plutovg static library build helpers
static const char *plutovg_sources[] = {
"vendor/lunasvg/plutovg/source/plutovg-blend.c",
"vendor/lunasvg/plutovg/source/plutovg-canvas.c",
"vendor/lunasvg/plutovg/source/plutovg-font.c",
"vendor/lunasvg/plutovg/source/plutovg-ft-math.c",
"vendor/lunasvg/plutovg/source/plutovg-ft-raster.c",
"vendor/lunasvg/plutovg/source/plutovg-ft-stroker.c",
"vendor/lunasvg/plutovg/source/plutovg-matrix.c",
"vendor/lunasvg/plutovg/source/plutovg-paint.c",
"vendor/lunasvg/plutovg/source/plutovg-path.c",
"vendor/lunasvg/plutovg/source/plutovg-rasterize.c",
"vendor/lunasvg/plutovg/source/plutovg-surface.c",
};
static const char *lunasvg_sources[] = {
"vendor/lunasvg/source/graphics.cpp",
"vendor/lunasvg/source/lunasvg.cpp",
"vendor/lunasvg/source/svgelement.cpp",
"vendor/lunasvg/source/svggeometryelement.cpp",
"vendor/lunasvg/source/svglayoutstate.cpp",
"vendor/lunasvg/source/svgpaintelement.cpp",
"vendor/lunasvg/source/svgparser.cpp",
"vendor/lunasvg/source/svgproperty.cpp",
"vendor/lunasvg/source/svgrenderstate.cpp",
"vendor/lunasvg/source/svgtextelement.cpp",
};
////////////////////////////////
// FreeType source files
@@ -65,7 +95,7 @@ static bool embed_font_file(const char *ttf_path, const char *header_path) {
#ifdef __APPLE__
////////////////////////////////
// macOS build (clang with Objective-C)
// macOS build (clang++ with Objective-C++)
static const char *frameworks[] = {
"-framework", "Metal",
@@ -77,6 +107,128 @@ static const char *frameworks[] = {
"-framework", "CoreFoundation",
};
static bool build_lunasvg_lib(const char *build_dir, bool debug) {
const char *obj_dir = nob_temp_sprintf("%s/lunasvg_obj", build_dir);
const char *lib_path = "vendor/lunasvg/liblunasvg.a";
// Collect all source paths to check if rebuild is needed
{
const char *all_sources[NOB_ARRAY_LEN(plutovg_sources) + NOB_ARRAY_LEN(lunasvg_sources)];
size_t n = 0;
for (size_t i = 0; i < NOB_ARRAY_LEN(plutovg_sources); i++)
all_sources[n++] = plutovg_sources[i];
for (size_t i = 0; i < NOB_ARRAY_LEN(lunasvg_sources); i++)
all_sources[n++] = lunasvg_sources[i];
if (!nob_needs_rebuild(lib_path, all_sources, n)) {
nob_log(NOB_INFO, "lunasvg is up to date");
return true;
}
}
if (!nob_mkdir_if_not_exists(obj_dir)) return false;
// Compile plutovg C sources
for (size_t i = 0; i < NOB_ARRAY_LEN(plutovg_sources); i++) {
const char *src = plutovg_sources[i];
// Extract filename for .o
const char *base = strrchr(src, '/');
base = base ? base + 1 : src;
char obj_name[256];
snprintf(obj_name, sizeof(obj_name), "%s", base);
char *dot = strrchr(obj_name, '.');
if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
const char *obj_path = nob_temp_sprintf("%s/%s", obj_dir, obj_name);
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "clang");
nob_cmd_append(&cmd, "-std=c11", "-c");
nob_cmd_append(&cmd, "-DPLUTOVG_BUILD", "-DPLUTOVG_BUILD_STATIC");
nob_cmd_append(&cmd, "-Ivendor/lunasvg/plutovg/include");
nob_cmd_append(&cmd, "-Ivendor/lunasvg/plutovg/source");
nob_cmd_append(&cmd, "-Wall", "-Wno-unused-function", "-Wno-unused-parameter");
if (debug) {
nob_cmd_append(&cmd, "-g", "-O0");
} else {
nob_cmd_append(&cmd, "-O2");
}
nob_cmd_append(&cmd, "-o", obj_path);
nob_cmd_append(&cmd, src);
Nob_Cmd_Opt copt = {0};
if (!nob_cmd_run_opt(&cmd, copt)) return false;
}
// Compile lunasvg C++ sources
for (size_t i = 0; i < NOB_ARRAY_LEN(lunasvg_sources); i++) {
const char *src = lunasvg_sources[i];
const char *base = strrchr(src, '/');
base = base ? base + 1 : src;
char obj_name[256];
snprintf(obj_name, sizeof(obj_name), "%s", base);
char *dot = strrchr(obj_name, '.');
if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
const char *obj_path = nob_temp_sprintf("%s/%s", obj_dir, obj_name);
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "clang++");
nob_cmd_append(&cmd, "-std=c++17", "-c");
nob_cmd_append(&cmd, "-fno-exceptions", "-fno-rtti");
nob_cmd_append(&cmd, "-DLUNASVG_BUILD", "-DLUNASVG_BUILD_STATIC", "-DPLUTOVG_BUILD_STATIC");
nob_cmd_append(&cmd, "-Ivendor/lunasvg/include");
nob_cmd_append(&cmd, "-Ivendor/lunasvg/source");
nob_cmd_append(&cmd, "-Ivendor/lunasvg/plutovg/include");
nob_cmd_append(&cmd, "-Wall", "-Wno-unused-function", "-Wno-unused-parameter");
if (debug) {
nob_cmd_append(&cmd, "-g", "-O0");
} else {
nob_cmd_append(&cmd, "-O2");
}
nob_cmd_append(&cmd, "-o", obj_path);
nob_cmd_append(&cmd, src);
Nob_Cmd_Opt copt = {0};
if (!nob_cmd_run_opt(&cmd, copt)) return false;
}
// Archive into static library
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "ar", "rcs", lib_path);
for (size_t i = 0; i < NOB_ARRAY_LEN(plutovg_sources); i++) {
const char *src = plutovg_sources[i];
const char *base = strrchr(src, '/');
base = base ? base + 1 : src;
char obj_name[256];
snprintf(obj_name, sizeof(obj_name), "%s", base);
char *dot = strrchr(obj_name, '.');
if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
nob_cmd_append(&cmd, nob_temp_sprintf("%s/%s", obj_dir, obj_name));
}
for (size_t i = 0; i < NOB_ARRAY_LEN(lunasvg_sources); i++) {
const char *src = lunasvg_sources[i];
const char *base = strrchr(src, '/');
base = base ? base + 1 : src;
char obj_name[256];
snprintf(obj_name, sizeof(obj_name), "%s", base);
char *dot = strrchr(obj_name, '.');
if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
nob_cmd_append(&cmd, nob_temp_sprintf("%s/%s", obj_dir, obj_name));
}
Nob_Cmd_Opt copt = {0};
if (!nob_cmd_run_opt(&cmd, copt)) return false;
}
// Clean up obj dir — only the .a is needed
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "rm", "-rf", obj_dir);
Nob_Cmd_Opt copt = {0};
nob_cmd_run_opt(&cmd, copt);
}
nob_log(NOB_INFO, "Built %s", lib_path);
return true;
}
static bool build_freetype_lib(const char *build_dir, bool debug) {
const char *obj_dir = nob_temp_sprintf("%s/freetype_obj", build_dir);
const char *lib_path = "vendor/freetype/libfreetype.a";
@@ -168,6 +320,7 @@ int main(int argc, char **argv) {
Nob_Cmd_Opt opt = {0}; nob_cmd_run_opt(&cmd, opt); }
{ Nob_Cmd cmd = {0}; nob_cmd_append(&cmd, "rm", "-rf", "build_release");
Nob_Cmd_Opt opt = {0}; nob_cmd_run_opt(&cmd, opt); }
remove("vendor/lunasvg/liblunasvg.a");
remove("vendor/freetype/libfreetype.a");
remove("src/renderer/font_inter.gen.h");
return 0;
@@ -187,22 +340,25 @@ int main(int argc, char **argv) {
if (!nob_mkdir_if_not_exists(res_dir)) return 1;
// Build static libraries
if (!build_lunasvg_lib(build_dir, debug)) return 1;
if (!build_freetype_lib(build_dir, debug)) return 1;
// Generate embedded font header
if (!embed_font_file("assets/fonts/Inter-Regular.ttf",
"src/renderer/font_inter.gen.h")) return 1;
// Unity build: single clang invocation compiles main.c (which #includes everything)
// Unity build: single clang++ invocation compiles main.cpp (which #includes everything)
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "clang");
nob_cmd_append(&cmd, "-std=c11", "-x", "objective-c");
nob_cmd_append(&cmd, "clang++");
nob_cmd_append(&cmd, "-std=c++20", "-x", "objective-c++");
nob_cmd_append(&cmd, "-fno-exceptions", "-fno-rtti");
nob_cmd_append(&cmd, "-Wall", "-Wextra", "-Wno-missing-field-initializers");
nob_cmd_append(&cmd, "-Wno-deprecated-declarations");
nob_cmd_append(&cmd, "-Isrc", "-Ivendor/clay");
nob_cmd_append(&cmd, "-Ivendor/nanosvg");
nob_cmd_append(&cmd, "-Ivendor/lunasvg/include");
nob_cmd_append(&cmd, "-Ivendor/freetype/include");
nob_cmd_append(&cmd, "-DLUNASVG_BUILD_STATIC");
if (debug) {
nob_cmd_append(&cmd, "-g", "-O0", "-D_DEBUG");
@@ -211,10 +367,11 @@ int main(int argc, char **argv) {
}
nob_cmd_append(&cmd, "-o", binary_path);
nob_cmd_append(&cmd, "src/main.c");
nob_cmd_append(&cmd, "src/main.cpp");
// Reset language mode so .a is treated as a library, not source
nob_cmd_append(&cmd, "-x", "none");
nob_cmd_append(&cmd, "vendor/lunasvg/liblunasvg.a");
nob_cmd_append(&cmd, "vendor/freetype/libfreetype.a");
{
@@ -222,7 +379,7 @@ int main(int argc, char **argv) {
for (i = 0; i < NOB_ARRAY_LEN(frameworks); i++)
nob_cmd_append(&cmd, frameworks[i]);
}
nob_cmd_append(&cmd, "-lm");
nob_cmd_append(&cmd, "-lstdc++");
{ Nob_Cmd_Opt opt = {0}; if (!nob_cmd_run_opt(&cmd, opt)) return 1; }
}
@@ -377,6 +534,92 @@ static bool compile_and_embed_shaders(const char *build_dir) {
return true;
}
static bool build_lunasvg_lib(const char *build_dir, bool debug) {
const char *obj_dir = nob_temp_sprintf("%s\\lunasvg_obj", build_dir);
const char *lib_path = debug ? "vendor\\lunasvg\\lunasvg_d.lib" : "vendor\\lunasvg\\lunasvg.lib";
// Check if rebuild is needed
{
const char *all_sources[NOB_ARRAY_LEN(plutovg_sources) + NOB_ARRAY_LEN(lunasvg_sources)];
size_t n = 0;
for (size_t i = 0; i < NOB_ARRAY_LEN(plutovg_sources); i++)
all_sources[n++] = plutovg_sources[i];
for (size_t i = 0; i < NOB_ARRAY_LEN(lunasvg_sources); i++)
all_sources[n++] = lunasvg_sources[i];
if (!nob_needs_rebuild(lib_path, all_sources, n)) {
nob_log(NOB_INFO, "lunasvg is up to date");
return true;
}
}
if (!nob_mkdir_if_not_exists(obj_dir)) return false;
// Compile plutovg C sources
for (size_t i = 0; i < NOB_ARRAY_LEN(plutovg_sources); i++) {
const char *src = plutovg_sources[i];
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "cl.exe", "/nologo", "/c");
nob_cmd_append(&cmd, "/std:c11");
nob_cmd_append(&cmd, "/DPLUTOVG_BUILD", "/DPLUTOVG_BUILD_STATIC");
nob_cmd_append(&cmd, "/Ivendor/lunasvg/plutovg/include");
nob_cmd_append(&cmd, "/Ivendor/lunasvg/plutovg/source");
nob_cmd_append(&cmd, "/W3");
if (debug) {
nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od");
} else {
nob_cmd_append(&cmd, "/MT", "/O2");
}
nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", obj_dir));
nob_cmd_append(&cmd, src);
Nob_Cmd_Opt copt = {0};
if (!nob_cmd_run_opt(&cmd, copt)) return false;
}
// Compile lunasvg C++ sources
for (size_t i = 0; i < NOB_ARRAY_LEN(lunasvg_sources); i++) {
const char *src = lunasvg_sources[i];
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "cl.exe", "/nologo", "/c");
nob_cmd_append(&cmd, "/std:c++17", "/EHsc");
nob_cmd_append(&cmd, "/DLUNASVG_BUILD", "/DLUNASVG_BUILD_STATIC", "/DPLUTOVG_BUILD_STATIC");
nob_cmd_append(&cmd, "/Ivendor/lunasvg/include");
nob_cmd_append(&cmd, "/Ivendor/lunasvg/source");
nob_cmd_append(&cmd, "/Ivendor/lunasvg/plutovg/include");
nob_cmd_append(&cmd, "/W3");
if (debug) {
nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od");
} else {
nob_cmd_append(&cmd, "/MT", "/O2");
}
nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", obj_dir));
nob_cmd_append(&cmd, src);
Nob_Cmd_Opt copt = {0};
if (!nob_cmd_run_opt(&cmd, copt)) return false;
}
// Archive into static library
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "lib.exe", "/nologo", nob_temp_sprintf("/OUT:%s", lib_path));
nob_cmd_append(&cmd, nob_temp_sprintf("%s/*.obj", obj_dir));
Nob_Cmd_Opt copt = {0};
if (!nob_cmd_run_opt(&cmd, copt)) return false;
}
// Clean up obj dir — only the .lib is needed
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "cmd.exe", "/c",
nob_temp_sprintf("if exist %s rmdir /s /q %s", obj_dir, obj_dir));
Nob_Cmd_Opt copt = {0};
nob_cmd_run_opt(&cmd, copt);
}
nob_log(NOB_INFO, "Built %s", lib_path);
return true;
}
static bool build_freetype_lib(const char *build_dir, bool debug) {
const char *obj_dir = nob_temp_sprintf("%s\\freetype_obj", build_dir);
const char *lib_path = debug ? "vendor\\freetype\\freetype_d.lib" : "vendor\\freetype\\freetype.lib";
@@ -397,7 +640,7 @@ static bool build_freetype_lib(const char *build_dir, bool debug) {
nob_cmd_append(&cmd, "/Ivendor/freetype/include");
nob_cmd_append(&cmd, "/W3");
if (debug) {
nob_cmd_append(&cmd, "/MTd", "/Zi");
nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od");
} else {
nob_cmd_append(&cmd, "/MT", "/O2");
}
@@ -454,6 +697,8 @@ int main(int argc, char **argv) {
{ Nob_Cmd cmd = {0}; nob_cmd_append(&cmd, "cmd.exe", "/c",
"if exist build_release rmdir /s /q build_release");
Nob_Cmd_Opt opt = {0}; nob_cmd_run_opt(&cmd, opt); }
remove("vendor\\lunasvg\\lunasvg.lib");
remove("vendor\\lunasvg\\lunasvg_d.lib");
remove("vendor\\freetype\\freetype.lib");
remove("vendor\\freetype\\freetype_d.lib");
remove("src\\renderer\\font_inter.gen.h");
@@ -465,6 +710,7 @@ int main(int argc, char **argv) {
if (!nob_mkdir_if_not_exists(build_dir)) return 1;
// Build static libraries
if (!build_lunasvg_lib(build_dir, debug)) return 1;
if (!build_freetype_lib(build_dir, debug)) return 1;
// Generate embedded font header
@@ -478,18 +724,19 @@ int main(int argc, char **argv) {
const char *vk_include = nob_temp_sprintf("/I%s/Include", vk_sdk);
const char *vk_lib = nob_temp_sprintf("%s/Lib/vulkan-1.lib", vk_sdk);
// Unity build: single cl.exe invocation compiles main.c (which #includes everything)
// Unity build: single cl.exe invocation compiles main.cpp (which #includes everything including the vulkan renderer)
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "cl.exe");
nob_cmd_append(&cmd, "/nologo", "/std:c11", "/TC", "/W3");
nob_cmd_append(&cmd, "/nologo", "/std:c++20", "/EHsc", "/W3");
nob_cmd_append(&cmd, "/Isrc", "/Ivendor/clay");
nob_cmd_append(&cmd, "/Ivendor/nanosvg");
nob_cmd_append(&cmd, "/Ivendor/lunasvg/include");
nob_cmd_append(&cmd, "/Ivendor/freetype/include");
nob_cmd_append(&cmd, vk_include);
nob_cmd_append(&cmd, "/DLUNASVG_BUILD_STATIC");
if (debug) {
nob_cmd_append(&cmd, "/MTd", "/Zi", "/D_DEBUG");
nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od", "/D_DEBUG");
} else {
nob_cmd_append(&cmd, "/MT", "/Zi", "/O2", "/DNDEBUG");
}
@@ -498,13 +745,14 @@ int main(int argc, char **argv) {
nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", build_dir));
nob_cmd_append(&cmd, nob_temp_sprintf("/Fd:%s/autosample.pdb", build_dir));
nob_cmd_append(&cmd, "src/main.c");
nob_cmd_append(&cmd, "src/main.cpp");
nob_cmd_append(&cmd, "/link");
nob_cmd_append(&cmd, "/MACHINE:X64");
nob_cmd_append(&cmd, "/SUBSYSTEM:CONSOLE");
nob_cmd_append(&cmd, nob_temp_sprintf("/PDB:%s/autosample.pdb", build_dir));
nob_cmd_append(&cmd, "/DEBUG");
nob_cmd_append(&cmd, debug ? "vendor/lunasvg/lunasvg_d.lib" : "vendor/lunasvg/lunasvg.lib");
nob_cmd_append(&cmd, debug ? "vendor/freetype/freetype_d.lib" : "vendor/freetype/freetype.lib");
nob_cmd_append(&cmd, vk_lib);
{