// Bootstrap:
// Windows: cl /nologo build.c
// macOS: cc build.c -o build
// After that, just run: ./build (or build.exe on Windows)
#define NOB_IMPLEMENTATION
#include "vendor/nob/nob.h"
#ifdef __APPLE__
////////////////////////////////
// macOS build (clang++ with Objective-C++)
static const char *frameworks[] = {
"-framework", "Metal",
"-framework", "Cocoa",
"-framework", "CoreAudio",
"-framework", "AudioToolbox",
"-framework", "CoreMIDI",
"-framework", "QuartzCore",
"-framework", "CoreText",
"-framework", "CoreFoundation",
"-framework", "CoreGraphics",
};
int main(int argc, char **argv) {
NOB_GO_REBUILD_URSELF(argc, argv);
bool debug = false;
bool clean = false;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "debug") == 0) debug = true;
else if (strcmp(argv[i], "clean") == 0) clean = true;
}
const char *build_dir = debug ? "build_debug" : "build_release";
if (clean) {
nob_log(NOB_INFO, "Cleaning %s/", build_dir);
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "rm", "-rf", build_dir);
{ Nob_Cmd_Opt opt = {0}; if (!nob_cmd_run_opt(&cmd, opt)) return 1; }
return 0;
}
// App bundle paths
const char *app_dir = nob_temp_sprintf("%s/autosample.app", build_dir);
const char *contents = nob_temp_sprintf("%s/Contents", app_dir);
const char *macos_dir = nob_temp_sprintf("%s/Contents/MacOS", app_dir);
const char *res_dir = nob_temp_sprintf("%s/Contents/Resources", app_dir);
const char *binary_path = nob_temp_sprintf("%s/Contents/MacOS/autosample", app_dir);
if (!nob_mkdir_if_not_exists(build_dir)) return 1;
if (!nob_mkdir_if_not_exists(app_dir)) return 1;
if (!nob_mkdir_if_not_exists(contents)) return 1;
if (!nob_mkdir_if_not_exists(macos_dir)) return 1;
if (!nob_mkdir_if_not_exists(res_dir)) return 1;
// 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=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");
if (debug) {
nob_cmd_append(&cmd, "-g", "-O0", "-D_DEBUG");
} else {
nob_cmd_append(&cmd, "-O2", "-DNDEBUG");
}
nob_cmd_append(&cmd, "-o", binary_path);
nob_cmd_append(&cmd, "src/main.cpp");
{
size_t i;
for (i = 0; i < NOB_ARRAY_LEN(frameworks); i++)
nob_cmd_append(&cmd, frameworks[i]);
}
{ Nob_Cmd_Opt opt = {0}; if (!nob_cmd_run_opt(&cmd, opt)) return 1; }
}
// Write Info.plist
{
const char *plist_path = nob_temp_sprintf("%s/Contents/Info.plist", app_dir);
nob_write_entire_file(plist_path,
"\n"
"\n"
"\n"
"\n"
" CFBundleExecutable\n"
" autosample\n"
" CFBundleIdentifier\n"
" com.autosample.app\n"
" CFBundleName\n"
" autosample\n"
" CFBundleVersion\n"
" 0.1\n"
" CFBundleShortVersionString\n"
" 0.1\n"
" CFBundlePackageType\n"
" APPL\n"
" NSHighResolutionCapable\n"
" \n"
" NSSupportsAutomaticGraphicsSwitching\n"
" \n"
"\n"
"\n",
strlen(
"\n"
"\n"
"\n"
"\n"
" CFBundleExecutable\n"
" autosample\n"
" CFBundleIdentifier\n"
" com.autosample.app\n"
" CFBundleName\n"
" autosample\n"
" CFBundleVersion\n"
" 0.1\n"
" CFBundleShortVersionString\n"
" 0.1\n"
" CFBundlePackageType\n"
" APPL\n"
" NSHighResolutionCapable\n"
" \n"
" NSSupportsAutomaticGraphicsSwitching\n"
" \n"
"\n"
"\n"
));
}
nob_log(NOB_INFO, "Build complete: %s", app_dir);
return 0;
}
#else
////////////////////////////////
// Windows build (MSVC cl.exe)
static const char *link_libs[] = {
"d3d12.lib",
"dxgi.lib",
"d3dcompiler.lib",
"user32.lib",
"gdi32.lib",
"shell32.lib",
"ole32.lib",
"advapi32.lib",
"dwmapi.lib",
"winmm.lib",
};
int main(int argc, char **argv) {
NOB_GO_REBUILD_URSELF(argc, argv);
bool debug = false;
bool clean = false;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "debug") == 0) debug = true;
else if (strcmp(argv[i], "clean") == 0) clean = true;
}
const char *build_dir = debug ? "build_debug" : "build_release";
if (clean) {
nob_log(NOB_INFO, "Cleaning %s/", build_dir);
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "cmd.exe", "/c",
nob_temp_sprintf("if exist %s rmdir /s /q %s", build_dir, build_dir));
{ Nob_Cmd_Opt opt = {0}; if (!nob_cmd_run_opt(&cmd, opt)) return 1; }
return 0;
}
if (!nob_mkdir_if_not_exists(build_dir)) return 1;
// Unity build: single cl.exe invocation compiles main.cpp (which #includes everything)
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "cl.exe");
nob_cmd_append(&cmd, "/nologo", "/std:c++20", "/EHsc", "/W3");
nob_cmd_append(&cmd, "/Isrc", "/Ivendor/clay");
if (debug) {
nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od", "/D_DEBUG");
} else {
nob_cmd_append(&cmd, "/MT", "/Zi", "/O2", "/DNDEBUG");
}
nob_cmd_append(&cmd, nob_temp_sprintf("/Fe:%s/autosample.exe", build_dir));
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.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");
{
size_t i;
for (i = 0; i < NOB_ARRAY_LEN(link_libs); i++)
nob_cmd_append(&cmd, link_libs[i]);
}
{ Nob_Cmd_Opt opt = {0}; if (!nob_cmd_run_opt(&cmd, opt)) return 1; }
}
// Clean up obj files
nob_delete_file(nob_temp_sprintf("%s/main.obj", build_dir));
nob_log(NOB_INFO, "Build complete: %s/autosample.exe", build_dir);
return 0;
}
#endif