From ed9036c373eca90cca125e68072d2a9eeb5e36fc Mon Sep 17 00:00:00 2001 From: jacob Date: Thu, 16 May 2024 23:50:57 -0500 Subject: [PATCH] beginning conversion from cmake to buildit --- CMakeLists.txt | 307 ------------------------- build.bat | 128 ----------- build.c | 590 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 590 insertions(+), 435 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 build.bat create mode 100644 build.c diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 93446c77..00000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,307 +0,0 @@ -cmake_minimum_required(VERSION 3.25.1) -project(powerplay) - -# Options below are laid out so that running cmake with all "OFF" results in the "release" / "user" build - -option(RTC "Should the build compile with runtime checks enabled (asserts, asan, etc.) - REQUIRES CRTLIB=ON" OFF) -option(ASAN "Should the build compile with the address sanitizer enabled (asserts, asan, etc.) - REQUIRES CRTLIB=ON" OFF) -option(CRTLIB "Should the build link with the CRTLIB" OFF) -option(DEBINFO "Should the build compile with debug info" OFF) -option(DEVELOPER "Should the build compile with developer mode enabled" OFF) -option(PROFILING "Should the build compile with profiling enabled - REQUIRES CRTLIB=ON, MSVC=OFF" OFF) -option(UNOPTIMIZED "Should the build compile with optimization disabled" OFF) -option(MSVC "Should the build compile using MSVC" OFF) - -################################################################################ -# Source files -################################################################################ - -# Glob source files -file(GLOB_RECURSE sources CONFIGURE_DEPENDS src/*.c src/*.cpp src/*.h) - -# Filter platform specific -list(FILTER sources EXCLUDE REGEX "sys_|renderer_|playback_|mp3_|ttf_") -if(PLATFORM_WIN32) - set(sources ${sources} src/sys_win32.c) - set(sources ${sources} src/renderer_d3d11.c) - set(sources ${sources} src/playback_wasapi.c) - set(sources ${sources} src/mp3_mmf.c) - set(sources ${sources} src/ttf_dwrite.cpp) - set(sources ${sources} .natvis) -endif() - -# Add tracy -list(FILTER sources EXCLUDE REGEX "third_party") -if(PROFILING) - set(sources ${sources} src/third_party/tracy/TracyClient.cpp) -endif() - -list(FILTER sources EXCLUDE REGEX "WIP") - -################################################################################ -# Resource embedding -################################################################################ - -set(inc_dependencies "") - -# Only archive & embed "res" dir if not compiling a developer build -if(NOT DEVELOPER) - # Generate resource archive - set(resource_archive_path "${CMAKE_BINARY_DIR}/res.tar") - file(GLOB_RECURSE resource_sources CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/res/*) - add_custom_command( - OUTPUT ${resource_archive_path} - COMMAND cmake -E tar cvf ${resource_archive_path} . - DEPENDS ${resource_sources} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/res - ) - list(APPEND inc_dependencies ${resource_archive_path}) -endif() - -# Generate shaders archive -set(shaders_archive_path "${CMAKE_BINARY_DIR}/shaders.tar") -file(GLOB_RECURSE shader_sources CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/src/shaders/*) -add_custom_command( - OUTPUT ${shaders_archive_path} - COMMAND cmake -E tar cvf ${shaders_archive_path} . - DEPENDS ${shader_sources} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src/shaders -) -list(APPEND inc_dependencies ${shaders_archive_path}) - -set_source_files_properties(src/inc.c OBJECT_DEPENDS "${inc_dependencies}") - -################################################################################ -# RC file (windows) -################################################################################ - -set(rc_res_sources "") -if(PLATFORM_WIN32) - set(RC_PATH "${CMAKE_BINARY_DIR}/rc.rc") - set(RC_RES_PATH "${CMAKE_BINARY_DIR}/rc.res") - - # Add icon resource to .rc - set(ICON_SOURCE_PATH "${CMAKE_SOURCE_DIR}/icon.ico") - set(ICON_COPY_PATH "${CMAKE_BINARY_DIR}/icon.ico") - if(EXISTS ${ICON_SOURCE_PATH}) - # Copy icon to output dir - add_custom_command( - OUTPUT ${ICON_COPY_PATH} - COMMAND ${CMAKE_COMMAND} -E copy ${ICON_SOURCE_PATH} ${ICON_COPY_PATH} - DEPENDS ${ICON_SOURCE_PATH} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - ) - - # Insert icon into .rc - add_custom_command( - OUTPUT ${RC_PATH} - COMMAND break > ${RC_PATH} - COMMAND echo IDI_ICON ICON DISCARDABLE icon.ico >> ${RC_PATH} - DEPENDS ${ICON_COPY_PATH} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - ) - - # Compile rc.rc -> rc.res - add_custom_command( - OUTPUT ${RC_RES_PATH} - COMMAND llvm-rc ${RC_PATH} - DEPENDS ${ICON_COPY_PATH} ${RC_PATH} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - ) - add_custom_target(build_rc_res ALL DEPENDS ${RC_RES_PATH}) - - # Add to list of res_sources - set(rc_res_sources ${rc_res_sources} ${RC_RES_PATH}) - endif() -endif() - -################################################################################ -# Executable -################################################################################ - -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) - -# Add executable -add_executable(powerplay_exe WIN32 ${sources}) -set_target_properties( - powerplay_exe PROPERTIES - C_STANDARD 99 - OUTPUT_NAME "PowerPlay.exe" -) - -# Add precompiled header -target_precompile_headers(powerplay_exe PRIVATE src/common.h) - -################################################################################ -# Compiler flags -################################################################################ - -# TODO: -# Enable - -# -Wconversion \ -# -Wno-sign-conversion \ - -if (MSVC) - set(COMPILER_WARNINGS "") - - set(COMPILER_AND_LINKER_FLAGS) - - set(COMPILER_FLAGS) - - set(LINKER_FLAGS "${rc_res_sources} /subsystem:windows") - - set(C_VERSION "/std:c11") - set(CPP_VERSION "/std:c++20") -else() - set(COMPILER_WARNINGS " \ - -Weverything -Werror \ - -Wframe-larger-than=65536 \ - \ - -Wno-unused-macros -Wno-gnu-zero-variadic-macro-arguments -Wno-documentation \ - -Wno-old-style-cast -Wno-conversion -Wno-sign-conversion \ - -Wno-declaration-after-statement -Wno-extra-semi -Wno-extra-semi-stmt \ - -Wno-bad-function-cast -Wno-class-varargs -Wno-unreachable-code-break \ - -Wno-cast-align -Wno-float-equal -Wno-zero-as-null-pointer-constant \ - -Wno-cast-qual -Wno-missing-noreturn -Wno-missing-field-initializers \ - -Wno-missing-braces -Wno-initializer-overrides \ - -Wno-c99-extensions -Wno-c++98-compat-pedantic -Wno-c++98-compat \ - -Wno-switch-enum -Wno-switch-default \ - -Wno-reserved-identifier -Wno-reserved-macro-identifier \ - -Wno-unsafe-buffer-usage -Wno-writable-strings \ - ") - # -Wno-unused-vfariable -Wno-unused-but-set-variable -Wno-unused-parameter - - set(COMPILER_AND_LINKER_FLAGS " - -fuse-ld=lld-link \ - -nostdlib \ - -fno-strict-aliasing \ - -fno-finite-loops \ - -fwrapv \ - -msse4.2 \ - ") - - set(COMPILER_FLAGS) - - set(LINKER_FLAGS " \ - ${rc_res_sources} \ - -fno-strict-aliasing \ - -fno-finite-loops \ - -fwrapv \ - -msse4.2 \ - ") - - set(C_VERSION "-std=c99") - set(CPP_VERSION "-std=c++20") -endif() - -# RTC (Runtime checks) -if (RTC) - if (NOT CRTLIB) - message(FATAL_ERROR "CRTLIB (C runtime library) Must be enabled when compiling with RTC (runtime checks)") - endif() - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DRTC=1") - if (MSVC) - if (NOT ASAN) - # Enable RTC (not compatible with ASAN) - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} /RTCcsu") - endif() - else() - # Enable UBSan - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -fsanitize=undefined -fsanitize-trap=all") - # set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -fsanitize=undefined -DRTC=1") - endif() -endif() - -# CRTLIB (C runtime library) -if (CRTLIB) - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DCRTLIB=1") - if (RTC) - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -D_DEBUG -D_MT -D_DLL") - if (MSVC) - set(LINKER_FLAGS "${LINKER_FLAGS} msvcrtd.lib ucrtd.lib msvcprtd.lib vcruntime.lib") - else() - set(LINKER_FLAGS "${LINKER_FLAGS} -lmsvcrtd -lucrtd -lmsvcprtd -lvcruntimed") - endif() - else() - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -D_MT -D_DLL") - if (MSVC) - set(LINKER_FLAGS "${LINKER_FLAGS} msvcrt.lib ucrt.lib msvcprt.lib vcruntime.lib ") - else() - set(LINKER_FLAGS "${LINKER_FLAGS} -lmsvcrt -lucrt -lmsvcprt -lvcruntime") - endif() - endif() -else() - if (MSVC) - message(FATAL_ERROR "TODO") - else() - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -mno-stack-arg-probe -fno-builtin") - endif() -endif() - -# Optimization -if (UNOPTIMIZED) - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DUNOPTIMIZED=1") - if (MSVC) - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} /Od") - else() - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -O0") - endif() -else() - if (MSVC) - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} /O2 /LTCG") - else() - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -O3 -flto") - endif() -endif() - -# Debug info -if (DEBINFO) - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DDEBINFO=1") - if (MSVC) - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} /Zi") - else() - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -g") - endif() -endif() - -# ASAN -if (ASAN) - if (NOT CRTLIB) - message(FATAL_ERROR "CRTLIB (C runtime library) Must be enabled when compiling with ASAN") - endif() - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DASAN=1") - if (MSVC) - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} /fsanitize=address") - else() - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -fsanitize=address -shared-libasan") - endif() -endif() - -# Developer mode -if(DEVELOPER) - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DDEVELOPER=1") -endif() - -# Profiling -if(PROFILING) - if (NOT CRTLIB) - message(FATAL_ERROR "CRTLIB (C runtime library) Must be enabled when compiling with PROFILING") - endif() - if (MSVC) - message(FATAL_ERROR "MSVC not supported with PROFILING enabled (Profiling relies on Clang attributes)") - endif() - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DPROFILING=1") - - # Tracy flags - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DTRACY_ENABLE=1") - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DTRACY_CALLSTACK=5") - set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DTRACY_NO_SAMPLING -DTRACY_NO_SYSTEM_TRACING -DTRACY_NO_CALLSTACK") - # Disable warnings when compiling tracy client - set(COMPILER_WARNINGS "-Wno-everything") -endif() - -set(CMAKE_C_FLAGS "${COMPILER_AND_LINKER_FLAGS} ${COMPILER_FLAGS} ${COMPILER_WARNINGS} ${C_VERSION}") -set(CMAKE_CXX_FLAGS "${COMPILER_AND_LINKER_FLAGS} ${COMPILER_FLAGS} ${COMPILER_WARNINGS} ${CPP_VERSION}") -set(CMAKE_EXE_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} ${LINKER_FLAGS}") diff --git a/build.bat b/build.bat deleted file mode 100644 index 89b538ea..00000000 --- a/build.bat +++ /dev/null @@ -1,128 +0,0 @@ -@echo off -setlocal - -:: Description of command line arguments (disabled by default): -:: "debug" The target is intended to run in a debugger with debug info and optimizations disabled -:: "developer" The target will include all developer tooling -:: "profiling" The target will be compiled with profiling markup -:: "asan" The target will compile with address sanitizer enabled -:: "msvc" Compile with MSVC instead of Clang - -for %%a in (%*) do set "%%a=1" - -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -:: Verify environment -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - -if "%Platform%" neq "x64" ( - echo ERROR: Platform is not "x64" - please run this from the MSVC x64 native tools command prompt. - exit /b 1 -) - -if "%msvc%" == "1" ( - where /q cl.exe || ( - echo ERROR: "cl.exe" not found. - exit /b 1 - ) -) else ( - where /q clang.exe || ( - echo ERROR: "clang.exe" not found. - exit /b 1 - ) - - where /q lld-link || ( - echo ERROR: "lld-link.exe" not found. - exit /b 1 - ) -) - -where /q ninja.exe || ( - echo ERROR: "ninja.exe" not found. - exit /b 1 -) - -where /q cmake || ( - echo ERROR: "cmake.exe" not found. - exit /b 1 -) - -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -:: Choose configuration from args -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - -:: Must explicitly pass disabled CMake options or else missing options are -:: assumed to be equal to the value from the last build -set cmake_options_zero=-DRTC=0 -DASAN=0 -DCRTLIB=0 -DDEBINFO=0 -DDEVELOPER=0 -DPROFILING=0 -DUNOPTIMIZED=0 -DMSVC=0 - -set cmake_options_enabled= - -echo ======================================== - -if "%msvc%" == "1" ( - echo [Msvc] - set cmake_options_enabled=%cmake_options_enabled% -DMSVC=1 -) else ( - echo [Clang] -) - -if "%debug%" == "1" ( - echo [Debug build] - set cmake_options_enabled=%cmake_options_enabled% -DRTC=1 -DCRTLIB=1 -DDEBINFO=1 -DUNOPTIMIZED=1 -) else ( - echo [Release build] -) - -if "%developer%" == "1" ( - echo [Developer build] - set cmake_options_enabled=%cmake_options_enabled% -DDEVELOPER=1 -) else ( - echo [User build] -) - -if "%profiling%" == "1" ( - echo [Profiling enabled] - set cmake_options_enabled=%cmake_options_enabled% -DPROFILING=1 -DCRTLIB=1 -DDEBINFO=1 -) - -if "%asan%" == "1" ( - echo [Address sanitizer enabled] - set cmake_options_enabled=%cmake_options_enabled% -DASAN=1 -DCRTLIB=1 -DDEBINFO=1 -) - -echo ======================================== - -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -:: Build -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - -if not exist "build" mkdir build - -if "%msvc%" == "1" ( - cmake -H. -G Ninja -B build %cmake_options_zero% %cmake_options_enabled%^ - -DCMAKE_C_COMPILER:PATH="cl.exe"^ - -DCMAKE_CXX_COMPILER:PATH="cl.exe"^ - -DPLATFORM_WIN32=1 -) else ( - cmake -H. -G Ninja -B build %cmake_options_zero% %cmake_options_enabled%^ - -DCMAKE_C_COMPILER:PATH="clang.exe"^ - -DCMAKE_CXX_COMPILER:PATH="clang.exe"^ - -DCMAKE_C_COMPILER_ID="Clang"^ - -DCMAKE_CXX_COMPILER_ID="Clang"^ - -DCMAKE_SYSTEM_NAME="Generic"^ - -DPLATFORM_WIN32=1 -) - -if NOT %errorlevel% == 0 ( - echo. - echo ERROR: Configuration failed - exit /b 1 -) - -cmake --build build -:: cmake --build build -v - -if NOT %errorlevel% == 0 ( - echo. - echo ERROR: Build failed - exit /b 1 -) diff --git a/build.c b/build.c new file mode 100644 index 00000000..3061469a --- /dev/null +++ b/build.c @@ -0,0 +1,590 @@ +#define Rtc 1 +#include "buildit.h" + +#include + +/* Capabilities: + * + * Run commands. Return result of command. + * + * + */ + +/* ========================== * + * Globals + * ========================== */ + +/* ========================== * + * Args + * ========================== */ + +#define ARGS_XLIST(X) \ + X(CLANG, "clang", "Compile with clang") \ + X(MSVC, "msvc", "Compile with msvc") \ + X(RTC, "rtc", "Should the build compile with runtime checks enabled (asserts, asan, etc.) - Requires crtlib") \ + X(ASAN, "asan", "Should the build compile with the address sanitizer enabled (asserts, asan, etc.) - Requires crtlib") \ + X(CRTLIB, "crtlib", "Should the build link with the CRTLIB") \ + X(DEBINFO, "debinfo", "Should the build compile with debug info") \ + X(DEVELOPER, "developer", "Should the build compile with developer mode enabled") \ + X(PROFILING, "profiling", "Should the build compile with profiling enabled - Requires crtlib, clang") \ + X(UNOPTIMIZED, "unoptimized", "Should the build compile with optimization disabled") + +/* Make args global variables */ +#define X(id, str, desc) bool id = 0; +ARGS_XLIST(X) +#undef X + +/* Setup arg table */ +#define X(id, str, desc) _ARGID_ ## id, +enum ArgId { + ARGS_XLIST(X) + ARGS_COUNT +}; +#undef X + +typedef struct ArgEntry ArgEntry; +struct ArgEntry { + String name; + bool *var; +}; + +#define X(id, str, desc) [_ARGID_ ## id] = { .name = Lit(str), .var = &id }, +ArgEntry arg_entries[ARGS_COUNT] = { + ARGS_XLIST(X) +}; +#undef X + +/* ========================== * + * Util + * ========================== */ + +void Error(String msg) +{ + SH_PrintF(Lit("ERROR: %F\n"), FmtStr(msg)); +} + +/* ========================== * + * Compile command + * ========================== */ + +typedef struct CompileCommandListNode CompileCommandListNode; +struct CompileCommandListNode { + String comp_command; + String link_file_path; + CompileCommandListNode *next; + CompileCommandListNode *prev; +}; + +typedef struct CompileCommandList CompileCommandList; +struct CompileCommandList { + CompileCommandListNode *first; + CompileCommandListNode *last; + Size count; +}; + +void CompileCommandListAppend(Arena *arena, CompileCommandList *l, String comp_command, String link_file_path) +{ + CompileCommandListNode *n = ArenaPush(arena, CompileCommandListNode); + n->comp_command = comp_command; + n->link_file_path = link_file_path; + DllPushBack(l->first, l->last, n); + ++l->count; +} + +/* ========================== * + * Rc include + * ========================== */ + +typedef struct RcIncludeListNode RcIncludeListNode; +struct RcIncludeListNode { + D_Tag tag; + String rc_type; + RcIncludeListNode *next; + RcIncludeListNode *prev; +}; + +typedef struct RcIncludeList RcIncludeList; +struct RcIncludeList { + RcIncludeListNode *first; + RcIncludeListNode *last; + Size count; +}; + +void RcIncludeListAppend(Arena *arena, RcIncludeList *l, D_Tag tag, String rc_type) +{ + RcIncludeListNode *n = ArenaPush(arena, RcIncludeListNode); + n->tag = tag; + n->rc_type = rc_type; + DllPushBack(l->first, l->last, n); + ++l->count; +} + +/* ========================== * + * Build + * ========================== */ + +void OnBuild(StringList args_list) +{ + Arena arena = ArenaAlloc(Gigabyte(64)); + + CompileCommandList compile_command_list = { 0 }; + + String obj_file_extension = PlatformWindows ? Lit("obj") : Lit("o"); + D_Tag executable = D_FileTagFromPath(&arena, Lit("build/bin/PowerPlay.exe")); + + D_Tag pch_input = D_FileTagFromPath(&arena, Lit("src/common.h")); + D_Tag pch_c_output = D_FileTagFromPath(&arena, Lit("build/common_c.pch")); + D_Tag pch_cpp_output = D_FileTagFromPath(&arena, Lit("build/common_cpp.pch")); + + /* ========================== * + * Unpack command line args + * ========================== */ + + for (StringListNode *n = args_list.first; n; n = n->next) { + String arg_name = n->string; + for (int i = 0; i < ArrayCount(arg_entries); ++i) { + ArgEntry *entry = &arg_entries[i]; + if (StringEqual(arg_name, entry->name)) { + *entry->var = 1; + } + } + } + + if (MSVC && CLANG) { + Error(Lit("Msvc & clang arguments cannot both be set")); + OS_Exit(1); + } else if (!(MSVC || CLANG)) { + CLANG = 1; + } + + if (MSVC) CLANG = 0; + if (CLANG) MSVC = 0; + + /* ========================== * + * Determine compiler args + * ========================== */ + + String final_c_compile_args_fmt = { 0 }; + String final_cpp_compile_args_fmt = { 0 }; + String final_pch_c_compile_args_fmt = { 0 }; + String final_pch_cpp_compile_args_fmt = { 0 }; + String final_link_args_fmt = { 0 }; + + { + StringList warnings = { 0 }; + StringList compile_and_link_args = { 0 }; + StringList compile_args = { 0 }; + + StringList c_compile_args = { 0 }; + StringList cpp_compile_args = { 0 }; + StringList pch_c_compile_args = { 0 }; + StringList pch_cpp_compile_args = { 0 }; + + StringList link_args = { 0 }; + +#if 0 +#if Rtc + /* ========================== * + * Verify environment + * ========================== */ + { + I32 error = SH_RunCommand(Lit("where clang-cl.exe"), true); + if (error) { + StringListAppend(&arena, &compile_args, Lit("msdev &&")); + StringListAppend(&arena, &link_args, Lit("msdev &&")); + } + } + +#if 0 + { + /* TODO: Check for MSVC cl & rc */ + if (SH_RunCommand(Lit("where clang-cl.exe"), true)) { + Error(Lit("Could not locate clang-cl.exe")); + OS_Exit(1); + } + if (SH_RunCommand(Lit("where llvm-rc.exe"), true)) { + Error(Lit("Could not locate llvm-rc.exe")); + OS_Exit(1); + } + } +#endif +#endif +#endif + + if (CLANG) { +#if 1 + //StringListAppend(&arena, &compile_args, Lit("clang -c")); + //StringListAppend(&arena, &link_args, Lit("lld-link")); + + //StringListAppend(&arena, &c_compile_args, Lit("msdev && clang -c -o %F %F -std=c99")); + //StringListAppend(&arena, &pch_c_compile_args, Lit("msdev && clang -c -o %F %F -x c-header -std=c99")); + //StringListAppend(&arena, &cpp_compile_args, Lit("msdev && clang -c -o %F %F -std=c++20")); + //StringListAppend(&arena, &pch_cpp_compile_args, Lit("msdev && clang -c -o %F %F -x c++-header -std=c++20")); + StringListAppend(&arena, &c_compile_args, Lit("msdev && clang -xc -std=c99 -c %F -o %F")); + StringListAppend(&arena, &pch_c_compile_args, Lit("msdev && clang -xc-header -std=c99 -c %F -o %F")); + StringListAppend(&arena, &cpp_compile_args, Lit("msdev && clang -xc++ -std=c++20 -c %F -o %F")); + StringListAppend(&arena, &pch_cpp_compile_args, Lit("msdev && clang -xc++-header -std=c++20 -c %F -o %F")); + + StringListAppend(&arena, &link_args, Lit("msdev && clang %F -o %F")); +#else + StringListAppend(&arena, &compile_args, Lit("clang -c")); + StringListAppend(&arena, &link_args, Lit("lld-link")); + + StringListAppend(&arena, &c_compile_args, Lit("-std=c99")); + StringListAppend(&arena, &pch_c_compile_args, Lit("-x c-header -std=c99")); + StringListAppend(&arena, &cpp_compile_args, Lit("-std=c++20")); + StringListAppend(&arena, &pch_cpp_compile_args, Lit("-x c++-header -std=c++20")); + + StringListAppend(&arena, &compile_args, Lit("-o %F %F")); + StringListAppend(&arena, &link_args, Lit("%F")); +#endif + + //"-fuse-ld=lld-link" + + StringListAppend(&arena, + &compile_and_link_args, + Lit("-fuse-ld=lld-link " + "-nostdlib " + "-fno-strict-aliasing " + "-fno-finite-loops " + "-fwrapv " + "-msse4.1 " + "-msse4.2 ")); + + StringListAppend(&arena, + &warnings, + Lit("-Weverything -Werror " + "-Wframe-larger-than=65536 " + "-Wno-unused-macros -Wno-gnu-zero-variadic-macro-arguments -Wno-documentation " + "-Wno-old-style-cast -Wno-conversion -Wno-sign-conversion " + "-Wno-declaration-after-statement -Wno-extra-semi -Wno-extra-semi-stmt " + "-Wno-bad-function-cast -Wno-class-varargs -Wno-unreachable-code-break " + "-Wno-cast-align -Wno-float-equal -Wno-zero-as-null-pointer-constant " + "-Wno-cast-qual -Wno-missing-noreturn -Wno-missing-field-initializers " + "-Wno-missing-braces -Wno-initializer-overrides " + "-Wno-c99-extensions -Wno-c++98-compat-pedantic -Wno-c++98-compat " + "-Wno-switch-enum -Wno-switch-default " + "-Wno-reserved-identifier -Wno-reserved-macro-identifier " + "-Wno-unsafe-buffer-usage -Wno-writable-strings " + "" + "-Wno-double-promotion")); + + /* -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-parameter */ + + /* Pre-compiled header */ + StringListAppend(&arena, &c_compile_args, StringF(&arena, Lit("-include-pch %F"), FmtStr(pch_c_output.full_path))); + StringListAppend(&arena, &cpp_compile_args, StringF(&arena, Lit("-include-pch %F"), FmtStr(pch_cpp_output.full_path))); + } + + /* RTC */ + if (RTC) { + if (!CRTLIB) { + Error(Lit("CRTLIB (C runtime library) Must be enabled when compiling with RTC (runtime checks)")); + OS_Exit(1); + } + StringListAppend(&arena, &compile_and_link_args, Lit("-DRTC=1")); + if (MSVC) { + if (!ASAN) { + /* Enable /RTC option (not compatible with ASAN) */ + StringListAppend(&arena, &compile_and_link_args, Lit("/RTCcsu")); + } + } else { + /* Enable UBSan */ + StringListAppend(&arena, &compile_and_link_args, Lit("-fsanitize=undefined -fsanitize-trap=all")); + //StringListAppend(&compile_and_link_args, "-fsanitize=undefined"); + } + } + + /* CRTLIB */ + if (CRTLIB) { + StringListAppend(&arena, &compile_and_link_args, Lit("-DCRTLIB=1")); + String crt_libs = { 0 }; + if (MSVC) { + crt_libs = RTC ? + Lit("msvcrtd.lib ucrtd.lib msvcprtd.lib vcruntimed.lib") : + Lit("msvcrt.lib ucrt.lib msvcprt.lib vcruntime.lib"); + } else { + crt_libs = RTC ? + Lit("-lmsvcrtd -lucrtd -lmsvcprtd -lvcruntimed") : + Lit("-lmsvcrt -lucrt -lmsvcprt -lvcruntime"); + } + StringListAppend(&arena, &link_args, crt_libs); + } else { + if (MSVC) { + /* TODO */ + Error(Lit("TODO\n")); + OS_Exit(1); + } else { + StringListAppend(&arena, &compile_and_link_args, Lit("-mno-stack-arg-probe -fno-builtin")); + } + } + + /* Optimization */ + if (UNOPTIMIZED) { + StringListAppend(&arena, &compile_and_link_args, Lit("-DUNOPTIMIZED=1")); + StringListAppend(&arena, &compile_and_link_args, MSVC ? Lit("/Od") : Lit("-O0")); + } else { + StringListAppend(&arena, &compile_and_link_args, MSVC ? Lit("/O2 /LTCG") : Lit("-O3 -flto")); + } + + /* Debug info */ + if (DEBINFO) { + StringListAppend(&arena, &compile_and_link_args, Lit("-DDEBINFO=1")); + StringListAppend(&arena, &compile_and_link_args, MSVC ? Lit("/Zi") : Lit("-g")); + } + + /* Address sanitizer */ + if (ASAN) { + if (!CRTLIB) { + Error(Lit("CRTLIB (C runtime library) Must be enabled when compiling with asan enabled")); + OS_Exit(1); + } + StringListAppend(&arena, &compile_and_link_args, Lit("-DASAN=1")); + if (MSVC) { + /* TODO: Copy asan libs */ + StringListAppend(&arena, &compile_and_link_args, Lit("/fsanitize=address")); + } else { + StringListAppend(&arena, &compile_and_link_args, Lit("-fsanitize=address -shared-libasan")); + } + } + + /* Developer mode */ + if (DEVELOPER) { + StringListAppend(&arena, &compile_and_link_args, Lit("-DDEVELOPER=1")); + } + + /* Profiling */ + if (PROFILING) { + if (!CRTLIB) { + Error(Lit("CRTLIB (C runtime library) Must be enabled when compiling with profiling enabled")); + OS_Exit(1); + } + if (MSVC) { + Error(Lit("MSVC not supported with profiling enabled (Profiling relies on Clang attributes)")); + OS_Exit(1); + } + StringListAppend(&arena, &compile_and_link_args, Lit("-DPROFILING=1")); + /* Tracy flags */ + StringListAppend(&arena, &compile_and_link_args, Lit("-DTRACY_ENABLE=1")); + StringListAppend(&arena, &compile_and_link_args, Lit("-DTRACY_CALLSTACK=5")); + StringListAppend(&arena, &compile_and_link_args, Lit("-DTRACY_NO_SAMPLING -DTRACY_NO_SYSTEM_TRACING -DTRACY_NO_CALLSTACK")); + /* Disable warnings when compiling tracy client */ + warnings = (StringList) { 0 }; + } + + final_c_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), c_compile_args, compile_args, compile_and_link_args, warnings); + final_cpp_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), cpp_compile_args, compile_args, compile_and_link_args, warnings); + //final_pch_c_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), pch_c_compile_args, compile_args, compile_and_link_args, warnings); + //final_pch_cpp_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), pch_cpp_compile_args, compile_args, compile_and_link_args, warnings); + final_pch_c_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), pch_c_compile_args, compile_args, compile_and_link_args); + final_pch_cpp_compile_args_fmt = StringFromStringLists(&arena, Lit(" "), pch_cpp_compile_args, compile_args, compile_and_link_args); + final_link_args_fmt = StringFromStringLists(&arena, Lit(" "), link_args, compile_and_link_args, warnings); + } + + /* ========================== * + * Generate embeddable tar files + * ========================== */ + + bool embed_in_rc = !!MSVC; + + D_Tag res_dir = D_DirTagFromPath(&arena, Lit("res")); + D_Tag shaders_dir = D_DirTagFromPath(&arena, Lit("src/shaders")); + + D_Tag inc_file = D_FileTagFromPath(&arena, Lit("src/inc.c")); + RcIncludeList rc_includes = { 0 }; + + /* Generate shaders tar */ + D_Tag shaders_tar = D_FileTagFromPath(&arena, Lit("build/shaders.tar")); + D_AddDependency(shaders_tar, shaders_dir); + if (embed_in_rc) { + RcIncludeListAppend(&arena, &rc_includes, shaders_tar, Lit("RCDATA")); + } else { + D_AddDependency(inc_file, shaders_tar); + } + if (D_IsDirty(shaders_tar)) { + String tar_cmd = StringF(&arena, Lit("cd %F && tar cvf %F ."), FmtStr(shaders_dir.full_path), FmtStr(shaders_tar.full_path)); + SH_PrintF(Lit("Running command \"%F\"\n"), FmtStr(tar_cmd)); + I32 error = SH_RunCommand(tar_cmd, false); + } + + /* Generate res tar */ + if (!DEVELOPER) { + D_Tag res_tar = D_FileTagFromPath(&arena, Lit("build/res.tar")); + D_AddDependency(res_tar, res_dir); + if (embed_in_rc) { + RcIncludeListAppend(&arena, &rc_includes, res_tar, Lit("RCDATA")); + } else { + D_AddDependency(inc_file, res_tar); + } + if (D_IsDirty(res_tar)) { + String tar_cmd = StringF(&arena, Lit("cd %F && tar cvf %F ."), FmtStr(res_dir.full_path), FmtStr(res_tar.full_path)); + SH_PrintF(Lit("Running command \"%F\"\n"), FmtStr(tar_cmd)); + I32 error = SH_RunCommand(tar_cmd, false); + } + } + + /* ========================== * + * RC file (windows) + * ========================== */ + + if (PlatformWindows) { + D_Tag rc_file = D_FileTagFromPath(&arena, Lit("build/rc.rc")); + + /* Add icon file to rc list */ + { + D_Tag icon_file = D_FileTagFromPath(&arena, Lit("icon.ico")); + RcIncludeListAppend(&arena, &rc_includes, icon_file, Lit("ICON")); + } + + /* Add rc dependencies */ + for (RcIncludeListNode *rin = rc_includes.first; rin; rin = rin->next) { + D_AddDependency(rc_file, rin->tag); + } + + if (D_IsDirty(rc_file)) { + /* Generate rc file */ + D_ClearWrite(rc_file, Lit("")); + for (RcIncludeListNode *rin = rc_includes.first; rin; rin = rin->next) { + String name = D_GetName(rin->tag); + String line = StringF(&arena, Lit("%F %F DISCARDABLE %F\n"), FmtStr(name), FmtStr(rin->rc_type), FmtStr(name)); + D_AppendWrite(rc_file, line); + } + + /* Append rc -> res compile command */ + D_Tag rc_res_file = D_FileTagFromPath(&arena, Lit("build/rc.res")); + String rc_compile_cmd = { 0 }; + if (MSVC) { + rc_compile_cmd = StringF(&arena, Lit("msdev && rc %F"), FmtStr(rc_file.full_path)); + } else { + rc_compile_cmd = StringF(&arena, Lit("msdev && llvm-rc %F"), FmtStr(rc_file.full_path)); + } + CompileCommandListAppend(&arena, &compile_command_list, rc_compile_cmd, rc_res_file.full_path); + } + } + + /* ========================== * + * Add pch compile commands + * ========================== */ + + { + /* C */ + { + String comp_cmd = StringF(&arena, final_pch_c_compile_args_fmt, FmtStr(pch_input.full_path), FmtStr(pch_c_output.full_path)); + CompileCommandListAppend(&arena, &compile_command_list, comp_cmd, (String) { 0 }); + } + /* Cpp */ + { + String comp_cmd = StringF(&arena, final_pch_cpp_compile_args_fmt, FmtStr(pch_input.full_path), FmtStr(pch_cpp_output.full_path)); + CompileCommandListAppend(&arena, &compile_command_list, comp_cmd, (String) { 0 }); + } + } + + /* ========================== * + * Add src file compile commands + * ========================== */ + + D_Tag src_dir = D_DirTagFromPath(&arena, Lit("src")); + D_TagList src_files = D_GetDirContents(&arena, src_dir); + + for (D_TagListNode *n = src_files.first; n; n = n->next) { + D_Tag file = n->tag; + + bool include = !file.is_dir; + if (!include) continue; + + String name = D_GetName(file); + String extension = D_GetExtension(file); + bool is_c = StringEqual(extension, Lit("c")); + bool is_cpp = !is_c && StringEqual(extension, Lit("cpp")); + + include = (is_c || is_cpp) && D_IsDirty(file); + if (!include) continue; + + /* Determine platform specific source files */ + { + if (StringBeginsWith(name, Lit("sys_")) || + StringBeginsWith(name, Lit("renderer_")) || + StringBeginsWith(name, Lit("playback_")) || + StringBeginsWith(name, Lit("mp3_")) || + StringBeginsWith(name, Lit("ttf_"))) { + include = false; + if (PlatformWindows) { + include = StringEqual(name, Lit("sys_win32.c")) || + StringEqual(name, Lit("renderer_d3d11.c")) || + StringEqual(name, Lit("playback_wasapi.c")) || + StringEqual(name, Lit("mp3_mmf.c")) || + StringEqual(name, Lit("ttf_dwrite.cpp")); + } + } + + } + if (!include) continue; + + String obj_file_path = { 0 }; + { + String name_no_extension = name; + if ((extension.len + 1) <= name.len) { + name_no_extension.len -= extension.len + 1; + } + obj_file_path = StringF(&arena, Lit("build/%F.%F"), FmtStr(name_no_extension), FmtStr(obj_file_extension)); + obj_file_path = OS_GetAbsPath(&arena, obj_file_path); + } + + String comp_cmd_fmt = is_c ? final_c_compile_args_fmt : final_cpp_compile_args_fmt; + String comp_cmd = StringF(&arena, comp_cmd_fmt, FmtStr(file.full_path), FmtStr(obj_file_path)); + + CompileCommandListAppend(&arena, &compile_command_list, comp_cmd, obj_file_path); + } + + /* ========================== * + * Compile / link + * ========================== */ + + if (compile_command_list.first) { + StringList link_files = { 0 }; + + /* Compile */ + Size comp_i = 0; + Size comp_count = compile_command_list.count; + for (CompileCommandListNode *n = compile_command_list.first; n; n = n->next) { + ++comp_i; + String comp_cmd = n->comp_command; + if (comp_cmd.len > 0 ) { + //SH_PrintF(Lit("[Comp %F/%F] %F\n"), FmtI64(comp_i), FmtI64(comp_count), FmtStr(comp_cmd)); + SH_PrintF(Lit("[Comp %F/%F]\n"), FmtI64(comp_i), FmtI64(comp_count)); + SH_CommandResult result = SH_RunCommandCaptureOutput(&arena, comp_cmd, false); + if (result.error != 0) { + Error(Lit("Compilation failed")); + OS_Exit(1); + } + } + String link_file_path = n->link_file_path; + if (link_file_path.len > 0) { + StringListAppend(&arena, &link_files, link_file_path); + } + } + + /* Link */ + { + String link_files_str = StringFromStringList(&arena, Lit(" "), link_files); + String link_cmd = StringF(&arena, final_link_args_fmt, FmtStr(link_files_str), FmtStr(executable.full_path)); + //SH_PrintF(Lit("[Link] %F\n"), FmtStr(link_cmd)); + SH_Print(Lit("Linking...\n")); + SH_CommandResult result = SH_RunCommandCaptureOutput(&arena, link_cmd, false); + if (result.error != 0) { + Error(Lit("Linking failed")); + OS_Exit(1); + } + D_SetDirty(executable); + } + } else { + /* Nothing to build */ + SH_Print(Lit("Nothing to build")); + } + +#if 0 +#if Rtc + getchar(); +#endif +#endif +}