core layer
This commit is contained in:
1 parent
7542d9200d
commit
ee1878cce7
20 files changed
+1219
No files matched your search
@@ -44,6 +44,7 @@ IncludeCategories:
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseBlocks: true
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: 4
|
||||
InsertNewlineAtEOF: true
|
||||
MacroBlockBegin: ''
|
||||
@@ -57,6 +58,7 @@ PenaltyBreakString: 100
|
||||
PenaltyExcessCharacter: 1
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: 1
|
||||
SortIncludes: CaseInsensitive
|
||||
SpacesInAngles: Never
|
||||
SpacesInContainerLiterals: false
|
||||
|
||||
@@ -3,6 +3,7 @@ CompileFlags:
|
||||
- --driver-mode=cl
|
||||
- -Wno-unknown-pragmas
|
||||
- -Wno-unused-command-line-argument
|
||||
- /IJuliet
|
||||
Remove:
|
||||
- /Yu*
|
||||
- /Yc*
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
# Binaries
|
||||
[Bb]in/
|
||||
[Bb]uild/
|
||||
[Ll]ib/
|
||||
.idea/
|
||||
.vs/
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// ========================================================================= //
|
||||
// Includes
|
||||
|
||||
// Headers
|
||||
#include "core/core_inc.h"
|
||||
|
||||
// C
|
||||
#include "core/core_inc.c"
|
||||
|
||||
internal void entry_point() {}
|
||||
Whitespace-only changes.
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define internal static
|
||||
#define global static
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
typedef int8 bool8;
|
||||
typedef int16 bool16;
|
||||
typedef int32 bool32;
|
||||
typedef int64 bool64;
|
||||
@@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
// ========================================================================== //
|
||||
// Compiler defines | Clang
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
# define COMPILER_CLANG 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# else
|
||||
# error Compiler / OS combo is not supported
|
||||
# endif
|
||||
|
||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define ARCH_X64 1
|
||||
# else
|
||||
# error Architecture not supported
|
||||
# endif
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
# define COMPILER_MSVC 1
|
||||
|
||||
# if defined(_WIN32)
|
||||
# define OS_WINDOWS 1
|
||||
# else
|
||||
# error Compiler / OS combo is not supported
|
||||
# endif
|
||||
|
||||
# if defined(_M_AMD64)
|
||||
# define ARCH_X64 1
|
||||
# else
|
||||
# error Architecture not supported
|
||||
# endif
|
||||
|
||||
#else
|
||||
# error Compiler not supported.
|
||||
#endif
|
||||
|
||||
// ========================================================================== //
|
||||
// Language
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# define LANG_CPP 1
|
||||
#else
|
||||
# define LANG_C 1
|
||||
#endif
|
||||
|
||||
// ========================================================================== //
|
||||
// Build Options
|
||||
|
||||
#if !defined(BUILD_DEBUG)
|
||||
# define BUILD_DEBUG 1
|
||||
#endif
|
||||
|
||||
// ========================================================================== //
|
||||
// Zeroing unused Options
|
||||
|
||||
#if !defined(ARCH_X64)
|
||||
# define ARCH_X64 0
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_X86)
|
||||
# define ARCH_X86 0
|
||||
#endif
|
||||
|
||||
#if !defined(COMPILER_CLANG)
|
||||
# define COMPILER_CLANG 0
|
||||
#endif
|
||||
|
||||
#if !defined(COMPILER_MSVC)
|
||||
# define COMPILER_MSVC 0
|
||||
#endif
|
||||
|
||||
#if !defined(OS_WINDOWS)
|
||||
# define OS_WINDOWS 0
|
||||
#endif
|
||||
|
||||
#if !defined(LANG_CPP)
|
||||
# define LANG_CPP 0
|
||||
#endif
|
||||
|
||||
#if !defined(LANG_C)
|
||||
# define LANG_C 0
|
||||
#endif
|
||||
|
||||
#if !ARCH_X64
|
||||
# error Trying to build unsupported architecture. Only x64 is supported.
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
internal void entry_point();
|
||||
|
||||
internal void main_thread_core_entry_point(int argc, char** argv)
|
||||
{
|
||||
entry_point();
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
internal void main_thread_core_entry_point(int argc, char** argv);
|
||||
@@ -0,0 +1,10 @@
|
||||
// clang-format off
|
||||
#include "core_string.c"
|
||||
#include "core_entry_point.c"
|
||||
// clang-format on
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include "win32/core/win32_core.c"
|
||||
#elif
|
||||
# error Unsupported OS
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
// clang-format off
|
||||
#include "core_defines.h"
|
||||
|
||||
#include "core.h"
|
||||
#include "core_string.h"
|
||||
#include "core_entry_point.h"
|
||||
// clang-format on
|
||||
|
||||
#if OS_WINDOWS
|
||||
# include "win32/core/win32_core.h"
|
||||
#elif
|
||||
# error Unsupported OS
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
// ========================================================================== //
|
||||
// String Length
|
||||
internal uint64 cstring8_length(uint8* cstring)
|
||||
{
|
||||
uint64 length = 0;
|
||||
if (cstring)
|
||||
{
|
||||
uint8* p = cstring;
|
||||
for (; *p != '\0'; ++p)
|
||||
;
|
||||
length = (uint64)(p - cstring);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
internal uint64 cstring16_length(uint16* cstring)
|
||||
{
|
||||
uint64 length = 0;
|
||||
if (cstring)
|
||||
{
|
||||
uint16* p = cstring;
|
||||
for (; *p != '\0'; ++p)
|
||||
;
|
||||
length = (uint64)(p - cstring);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
internal uint64 cstring32_length(uint32* cstring)
|
||||
{
|
||||
uint64 length = 0;
|
||||
if (cstring)
|
||||
{
|
||||
uint32* p = cstring;
|
||||
for (; *p != '\0'; ++p)
|
||||
;
|
||||
length = (uint64)(p - cstring);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
// ========================================================================== //
|
||||
// String Constructor
|
||||
|
||||
internal String8 str8_cstring(uint8* cstring)
|
||||
{
|
||||
String8 result = { (uint8*)cstring, cstring8_length((uint8*)cstring) };
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String16 str16_cstring(uint16* cstring)
|
||||
{
|
||||
String16 result = { (uint16*)cstring, cstring16_length((uint16*)cstring) };
|
||||
return result;
|
||||
}
|
||||
|
||||
internal String32 str32_cstring(uint32* cstring)
|
||||
{
|
||||
String32 result = { (uint32*)cstring, cstring32_length((uint32*)cstring) };
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
// ========================================================================== //
|
||||
// String Types
|
||||
|
||||
typedef struct String8 String8;
|
||||
struct String8
|
||||
{
|
||||
uint8* str;
|
||||
uint64 size;
|
||||
};
|
||||
|
||||
typedef struct String16 String16;
|
||||
struct String16
|
||||
{
|
||||
uint16* str;
|
||||
uint64 size;
|
||||
};
|
||||
|
||||
typedef struct String32 String32;
|
||||
struct String32
|
||||
{
|
||||
uint32* str;
|
||||
uint64 size;
|
||||
};
|
||||
|
||||
// ========================================================================== //
|
||||
// String Length
|
||||
internal uint64 cstring8_length(uint8* cstring);
|
||||
internal uint64 cstring16_length(uint16* cstring);
|
||||
internal uint64 cstring32_length(uint32* cstring);
|
||||
|
||||
// ========================================================================== //
|
||||
// String Constructor
|
||||
|
||||
internal String16 str16_cstring(uint16* cstring);
|
||||
@@ -0,0 +1,17 @@
|
||||
internal void w32_entry_point(int argc, WCHAR** wargv)
|
||||
{
|
||||
char* argv[10];
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
String16 arg16 = str16_cstring((uint16*)wargv[i]);
|
||||
String8 arg8 = str8_from_16(args_arena, arg16);
|
||||
argv[i] = (char*)arg8.str;
|
||||
}
|
||||
main_thread_core_entry_point(argc, &argv);
|
||||
}
|
||||
|
||||
int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
|
||||
{
|
||||
w32_entry_point(__argc, __wargv);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#pragma comment(lib, "user32")
|
||||
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
call "%~dp0..\new_build.bat" %*
|
||||
exit /b %ERRORLEVEL%
|
||||
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
call "%~dp0..\new_generate.bat" %*
|
||||
exit /b %ERRORLEVEL%
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
cd /D "%~dp0"
|
||||
|
||||
:: --- Usage Notes -------------------------------------------------------------
|
||||
::
|
||||
:: Central build script for Juliet new module architecture (inspired by raddbg).
|
||||
:: Takes alphanumeric arguments to control target, compiler, and build configuration.
|
||||
::
|
||||
:: Examples:
|
||||
:: new_build
|
||||
:: new_build appbin
|
||||
:: new_build appbin clang
|
||||
:: new_build appbin release
|
||||
:: new_build appbin msvc debug asan
|
||||
:: new_build clean
|
||||
::
|
||||
|
||||
:: --- Unpack Arguments -------------------------------------------------------
|
||||
for %%a in (%*) do set "%%~a=1"
|
||||
|
||||
if "%clean%"=="1" (
|
||||
if exist build (
|
||||
echo [clean] Removing build directory...
|
||||
rmdir /s /q build
|
||||
)
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
:: --- Compiler Selection & Auto-Detection -------------------------------------
|
||||
if not "%msvc%"=="1" if not "%clang%"=="1" set clang=1
|
||||
|
||||
if "%msvc%"=="1" (
|
||||
where cl.exe >nul 2>nul
|
||||
if errorlevel 1 (
|
||||
if exist "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" (
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 >nul 2>&1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if not "%release%"=="1" set debug=1
|
||||
if "%debug%"=="1" set release=0 && echo [debug mode]
|
||||
if "%release%"=="1" set debug=0 && echo [release mode]
|
||||
if "%clang%"=="1" set msvc=0 && echo [clang compile]
|
||||
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
|
||||
|
||||
:: Default target: appbin
|
||||
if "%~1"=="" echo [default mode, assuming `appbin` build] && set appbin=1
|
||||
if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `appbin` build] && set appbin=1
|
||||
if "%~1"=="debug" if "%~2"=="" echo [default mode, assuming `appbin` build] && set appbin=1
|
||||
if "%~1"=="clang" if "%~2"=="" echo [default mode, assuming `appbin` build] && set appbin=1
|
||||
if "%~1"=="msvc" if "%~2"=="" echo [default mode, assuming `appbin` build] && set appbin=1
|
||||
|
||||
:: --- Unpack Command Line Build Arguments ------------------------------------
|
||||
set auto_compile_flags=
|
||||
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
||||
if "%ubsan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=undefined && echo [ubsan enabled]
|
||||
|
||||
:: --- Natvis Options ---------------------------------------------------------
|
||||
set natvis_flags=
|
||||
if exist "%~dp0Natvis\Juliet.natvis" (
|
||||
if "%msvc%"=="1" set natvis_flags=%natvis_flags% /NATVIS:"%~dp0Natvis\Juliet.natvis"
|
||||
if "%clang%"=="1" set natvis_flags=%natvis_flags% -Xlinker /NATVIS:"%~dp0Natvis\Juliet.natvis"
|
||||
)
|
||||
if exist "%~dp0Natvis\String.natvis" (
|
||||
if "%msvc%"=="1" set natvis_flags=%natvis_flags% /NATVIS:"%~dp0Natvis\String.natvis"
|
||||
if "%clang%"=="1" set natvis_flags=%natvis_flags% -Xlinker /NATVIS:"%~dp0Natvis\String.natvis"
|
||||
)
|
||||
|
||||
:: --- Compile/Link Line Definitions ------------------------------------------
|
||||
set cl_common= /I..\Juliet\ /nologo /FC /Z7 /Zc:preprocessor /utf-8
|
||||
set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
|
||||
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
|
||||
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /DEBUG %natvis_flags% /opt:ref /opt:icf
|
||||
set cl_out= /out:
|
||||
set cl_obj_out= /Fo:
|
||||
set cl_linker=
|
||||
|
||||
set clang_common= -mcx16 -I..\Juliet\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000
|
||||
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
|
||||
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags%
|
||||
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /DEBUG %natvis_flags% -Xlinker /opt:ref -Xlinker /opt:noicf
|
||||
set clang_out= -o
|
||||
set clang_obj_out= -o
|
||||
set clang_linker= -Xlinker
|
||||
|
||||
:: --- Per-Build Settings -----------------------------------------------------
|
||||
if "%msvc%"=="1" set linker=%cl_linker%
|
||||
if "%clang%"=="1" set linker=%clang_linker%
|
||||
if "%msvc%"=="1" set only_compile=/c
|
||||
if "%clang%"=="1" set only_compile=-c
|
||||
if "%msvc%"=="1" set link_dll=/link /DLL
|
||||
if "%clang%"=="1" set link_dll=-Xlinker -DLL
|
||||
|
||||
:: --- Choose Compile/Link Lines ----------------------------------------------
|
||||
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
||||
if "%msvc%"=="1" set compile_release=%cl_release%
|
||||
if "%msvc%"=="1" set compile_link=%cl_link%
|
||||
if "%msvc%"=="1" set out=%cl_out%
|
||||
if "%msvc%"=="1" set obj_out=%cl_obj_out%
|
||||
if "%clang%"=="1" set compile_debug=%clang_debug%
|
||||
if "%clang%"=="1" set compile_release=%clang_release%
|
||||
if "%clang%"=="1" set compile_link=%clang_link%
|
||||
if "%clang%"=="1" set out=%clang_out%
|
||||
if "%clang%"=="1" set obj_out=%clang_obj_out%
|
||||
if "%debug%"=="1" set compile=%compile_debug%
|
||||
if "%release%"=="1" set compile=%compile_release%
|
||||
|
||||
:: --- Prep Directories -------------------------------------------------------
|
||||
if not exist build mkdir build
|
||||
|
||||
:: --- Build Targets (@build_targets) -----------------------------------------
|
||||
pushd build
|
||||
if "%appbin%"=="1" set didbuild=1 && %compile% ..\Juliet\appbin\appbin_main.c %compile_link% %out%appbin.exe || exit /b 1
|
||||
popd
|
||||
|
||||
:: --- Warn On No Builds ------------------------------------------------------
|
||||
if "%didbuild%"=="" (
|
||||
echo [WARNING] no valid build target specified; must use build target names like `new_build appbin`.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [build success]
|
||||
exit /b 0
|
||||
@@ -0,0 +1,66 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
cd /D "%~dp0"
|
||||
|
||||
:: --- Usage Notes -------------------------------------------------------------
|
||||
::
|
||||
:: Generates clangd compile_commands.json and Visual Studio project/solution files.
|
||||
::
|
||||
:: Examples:
|
||||
:: new_generate (generates compile_commands.json and VS files)
|
||||
:: new_generate compile_commands (generates only compile_commands.json)
|
||||
:: new_generate vs (generates only vs/new_Juliet.sln and projects)
|
||||
::
|
||||
|
||||
set GEN_TOOL=misc\new_project_gen.exe
|
||||
set GEN_SRC=tools\new_project_gen.c
|
||||
|
||||
:: Auto-detect compiler for building the generator tool
|
||||
set COMPILER=
|
||||
where clang.exe >nul 2>nul
|
||||
if not errorlevel 1 (
|
||||
set COMPILER=clang
|
||||
) else (
|
||||
where cl.exe >nul 2>nul
|
||||
if not errorlevel 1 (
|
||||
set COMPILER=cl
|
||||
) else (
|
||||
if exist "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" (
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 >nul 2>&1
|
||||
)
|
||||
where cl.exe >nul 2>nul
|
||||
if not errorlevel 1 (
|
||||
set COMPILER=cl
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if "%COMPILER%"=="" (
|
||||
echo [ERROR] Neither clang nor cl found in PATH.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Recompile generator tool if needed
|
||||
set RECOMPILE=0
|
||||
if not exist "%GEN_TOOL%" set RECOMPILE=1
|
||||
if exist "Intermediate\new_project_gen.stamp" (
|
||||
set /p CACHED_STAMP=<"Intermediate\new_project_gen.stamp"
|
||||
for %%I in ("%GEN_SRC%") do (
|
||||
if "%%~tI_%%~zI" neq "!CACHED_STAMP!" set RECOMPILE=1
|
||||
)
|
||||
) else set RECOMPILE=1
|
||||
|
||||
if "!RECOMPILE!"=="1" (
|
||||
echo [GENERATE] Compiling %GEN_SRC% -^> %GEN_TOOL%...
|
||||
if not exist misc mkdir misc
|
||||
if not exist Intermediate mkdir Intermediate
|
||||
if "%COMPILER%"=="clang" (
|
||||
call clang -O2 -Wall -Wextra -Werror "%GEN_SRC%" -o "%GEN_TOOL%" || exit /b 1
|
||||
) else (
|
||||
call cl /nologo /O2 /W4 /WX "%GEN_SRC%" /Fe"%GEN_TOOL%" || exit /b 1
|
||||
)
|
||||
for %%I in ("%GEN_SRC%") do (echo %%~tI_%%~zI)>"Intermediate\new_project_gen.stamp"
|
||||
)
|
||||
|
||||
"%GEN_TOOL%" %*
|
||||
exit /b %ERRORLEVEL%
|
||||
@@ -0,0 +1,745 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define Assert(c) do { if (!(c)) { fprintf(stderr, "Assertion failed: %s at %s:%d\n", #c, __FILE__, __LINE__); abort(); } } while(0)
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
typedef struct FileNode
|
||||
{
|
||||
char path[512];
|
||||
struct FileNode* next;
|
||||
} FileNode;
|
||||
|
||||
typedef struct FileList
|
||||
{
|
||||
FileNode* first;
|
||||
FileNode* last;
|
||||
int32 count;
|
||||
} FileList;
|
||||
|
||||
typedef struct ProjectInfo
|
||||
{
|
||||
char name[64];
|
||||
char guid[64];
|
||||
FileList c_files;
|
||||
FileList h_files;
|
||||
} ProjectInfo;
|
||||
|
||||
static void file_list_push(FileList* list, const char* path)
|
||||
{
|
||||
Assert(list != NULL);
|
||||
Assert(path != NULL);
|
||||
|
||||
FileNode* node = (FileNode*)malloc(sizeof(FileNode));
|
||||
Assert(node != NULL);
|
||||
|
||||
strncpy_s(node->path, sizeof(node->path), path, _TRUNCATE);
|
||||
node->next = NULL;
|
||||
|
||||
if (list->last == NULL)
|
||||
{
|
||||
list->first = node;
|
||||
list->last = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
list->last->next = node;
|
||||
list->last = node;
|
||||
}
|
||||
list->count++;
|
||||
}
|
||||
|
||||
static void file_list_free(FileList* list)
|
||||
{
|
||||
Assert(list != NULL);
|
||||
|
||||
FileNode* curr = list->first;
|
||||
while (curr != NULL)
|
||||
{
|
||||
FileNode* next = curr->next;
|
||||
free(curr);
|
||||
curr = next;
|
||||
}
|
||||
list->first = NULL;
|
||||
list->last = NULL;
|
||||
list->count = 0;
|
||||
}
|
||||
|
||||
static void normalize_path_slashes_forward(char* path)
|
||||
{
|
||||
Assert(path != NULL);
|
||||
|
||||
for (int32 i = 0; path[i] != '\0'; i++)
|
||||
{
|
||||
if (path[i] == '\\')
|
||||
{
|
||||
path[i] = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void normalize_path_slashes_backward(char* path)
|
||||
{
|
||||
Assert(path != NULL);
|
||||
|
||||
for (int32 i = 0; path[i] != '\0'; i++)
|
||||
{
|
||||
if (path[i] == '/')
|
||||
{
|
||||
path[i] = '\\';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool str_ends_with_no_case(const char* str, const char* suffix)
|
||||
{
|
||||
Assert(str != NULL);
|
||||
Assert(suffix != NULL);
|
||||
|
||||
size_t str_len = strlen(str);
|
||||
size_t suffix_len = strlen(suffix);
|
||||
if (suffix_len > str_len)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* p = str + (str_len - suffix_len);
|
||||
return (_stricmp(p, suffix) == 0);
|
||||
}
|
||||
|
||||
static bool is_c_source_file(const char* path)
|
||||
{
|
||||
Assert(path != NULL);
|
||||
return str_ends_with_no_case(path, ".c") || str_ends_with_no_case(path, ".cpp");
|
||||
}
|
||||
|
||||
static bool is_c_header_file(const char* path)
|
||||
{
|
||||
Assert(path != NULL);
|
||||
return str_ends_with_no_case(path, ".h") || str_ends_with_no_case(path, ".hpp");
|
||||
}
|
||||
|
||||
static void find_files_recursive(const char* dir_path, FileList* out_list, bool include_headers)
|
||||
{
|
||||
Assert(dir_path != NULL);
|
||||
Assert(out_list != NULL);
|
||||
|
||||
char search_pattern[512];
|
||||
snprintf(search_pattern, sizeof(search_pattern), "%s\\*", dir_path);
|
||||
|
||||
WIN32_FIND_DATAA find_data;
|
||||
HANDLE find_handle = FindFirstFileA(search_pattern, &find_data);
|
||||
if (find_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (strcmp(find_data.cFileName, ".") == 0 || strcmp(find_data.cFileName, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char item_path[512];
|
||||
snprintf(item_path, sizeof(item_path), "%s\\%s", dir_path, find_data.cFileName);
|
||||
|
||||
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
find_files_recursive(item_path, out_list, include_headers);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_c_source_file(item_path) || (include_headers && is_c_header_file(item_path)))
|
||||
{
|
||||
char clean_path[512];
|
||||
strncpy_s(clean_path, sizeof(clean_path), item_path, _TRUNCATE);
|
||||
normalize_path_slashes_forward(clean_path);
|
||||
file_list_push(out_list, clean_path);
|
||||
}
|
||||
}
|
||||
} while (FindNextFileA(find_handle, &find_data));
|
||||
|
||||
FindClose(find_handle);
|
||||
}
|
||||
|
||||
static void generate_deterministic_guid(const char* input, char* out_guid, size_t out_guid_size)
|
||||
{
|
||||
Assert(input != NULL);
|
||||
Assert(out_guid != NULL);
|
||||
Assert(out_guid_size >= 37);
|
||||
|
||||
uint64 hash1 = 14695981039346656037ULL;
|
||||
uint64 hash2 = 1099511628211ULL;
|
||||
for (const char* c = input; *c != '\0'; ++c)
|
||||
{
|
||||
hash1 ^= (uint64)(*c);
|
||||
hash1 *= 1099511628211ULL;
|
||||
hash2 ^= (uint64)(*c);
|
||||
hash2 *= 137ULL;
|
||||
}
|
||||
|
||||
snprintf(out_guid, out_guid_size, "%08X-%04X-%04X-%04X-%012llX",
|
||||
(uint32)(hash1 >> 32),
|
||||
(uint32)((hash1 >> 16) & 0xFFFF),
|
||||
(uint32)(hash1 & 0xFFFF),
|
||||
(uint32)((hash2 >> 48) & 0xFFFF),
|
||||
(uint64)(hash2 & 0xFFFFFFFFFFFFULL));
|
||||
}
|
||||
|
||||
static bool write_entire_file(const char* path, const char* buffer, size_t size)
|
||||
{
|
||||
Assert(path != NULL);
|
||||
Assert(buffer != NULL);
|
||||
|
||||
HANDLE file_handle = CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (file_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fprintf(stderr, "[ERROR] Could not open file for writing: %s\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD bytes_written = 0;
|
||||
BOOL success = WriteFile(file_handle, buffer, (DWORD)size, &bytes_written, NULL);
|
||||
CloseHandle(file_handle);
|
||||
|
||||
return (success && bytes_written == (DWORD)size);
|
||||
}
|
||||
|
||||
static void get_normalized_cwd(char* out_cwd, size_t out_cwd_size, char* out_real_cwd, size_t out_real_size)
|
||||
{
|
||||
Assert(out_cwd != NULL);
|
||||
Assert(out_cwd_size > 0);
|
||||
|
||||
GetCurrentDirectoryA((DWORD)out_cwd_size, out_cwd);
|
||||
normalize_path_slashes_forward(out_cwd);
|
||||
|
||||
if (out_real_cwd != NULL && out_real_size > 0)
|
||||
{
|
||||
out_real_cwd[0] = '\0';
|
||||
HANDLE dir_handle = CreateFileA(".", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
if (dir_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
char real_path[512];
|
||||
DWORD len = GetFinalPathNameByHandleA(dir_handle, real_path, sizeof(real_path), FILE_NAME_NORMALIZED);
|
||||
CloseHandle(dir_handle);
|
||||
if (len > 0 && len < sizeof(real_path))
|
||||
{
|
||||
const char* p = real_path;
|
||||
if (strncmp(p, "\\\\?\\", 4) == 0)
|
||||
{
|
||||
p += 4;
|
||||
}
|
||||
strncpy_s(out_real_cwd, out_real_size, p, _TRUNCATE);
|
||||
normalize_path_slashes_forward(out_real_cwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void generate_compile_commands(void)
|
||||
{
|
||||
char cwd[512];
|
||||
char real_cwd[512];
|
||||
get_normalized_cwd(cwd, sizeof(cwd), real_cwd, sizeof(real_cwd));
|
||||
|
||||
size_t buf_cap = 8 * 1024 * 1024;
|
||||
char* json_buf = (char*)malloc(buf_cap);
|
||||
Assert(json_buf != NULL);
|
||||
|
||||
int32 offset = 0;
|
||||
offset += snprintf(json_buf + offset, buf_cap - offset, "[\n");
|
||||
|
||||
bool is_first = true;
|
||||
|
||||
// 1. Scan new Juliet modules (core, appbin, etc.)
|
||||
// We scan folders directly inside Juliet/, ignoring legacy 'src' and 'include'
|
||||
WIN32_FIND_DATAA find_data;
|
||||
HANDLE find_handle = FindFirstFileA("Juliet\\*", &find_data);
|
||||
if (find_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (strcmp(find_data.cFileName, ".") == 0 || strcmp(find_data.cFileName, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if (_stricmp(find_data.cFileName, "src") == 0 || _stricmp(find_data.cFileName, "include") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char module_dir[512];
|
||||
snprintf(module_dir, sizeof(module_dir), "Juliet\\%s", find_data.cFileName);
|
||||
|
||||
FileList module_files = {0};
|
||||
find_files_recursive(module_dir, &module_files, false);
|
||||
|
||||
char module_name[64];
|
||||
strncpy_s(module_name, sizeof(module_name), find_data.cFileName, _TRUNCATE);
|
||||
|
||||
char module_inc_flag[128] = "";
|
||||
char module_inc_disk_path[512];
|
||||
snprintf(module_inc_disk_path, sizeof(module_inc_disk_path), "Juliet\\%s\\%s_inc.h", module_name, module_name);
|
||||
if (_stricmp(module_name, "core") != 0 && GetFileAttributesA(module_inc_disk_path) != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
snprintf(module_inc_flag, sizeof(module_inc_flag), " \"/FI%s/%s_inc.h\",\n", module_name, module_name);
|
||||
}
|
||||
|
||||
for (FileNode* node = module_files.first; node != NULL; node = node->next)
|
||||
{
|
||||
const char* dirs_to_emit[2] = { cwd, (real_cwd[0] && _stricmp(cwd, real_cwd) != 0) ? real_cwd : NULL };
|
||||
|
||||
for (int32 d = 0; d < 2; d++)
|
||||
{
|
||||
if (dirs_to_emit[d] == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_first)
|
||||
{
|
||||
offset += snprintf(json_buf + offset, buf_cap - offset, ",\n");
|
||||
}
|
||||
is_first = false;
|
||||
|
||||
char full_file_path[512];
|
||||
snprintf(full_file_path, sizeof(full_file_path), "%s/%s", dirs_to_emit[d], node->path);
|
||||
|
||||
offset += snprintf(json_buf + offset, buf_cap - offset,
|
||||
" {\n"
|
||||
" \"directory\": \"%s\",\n"
|
||||
" \"file\": \"%s\",\n"
|
||||
" \"arguments\": [\n"
|
||||
" \"clang-cl.exe\",\n"
|
||||
" \"--driver-mode=cl\",\n"
|
||||
" \"/nologo\",\n"
|
||||
" \"/clang:-std=c11\",\n"
|
||||
" \"/W4\",\n"
|
||||
" \"/Wno-unused-function\",\n"
|
||||
" \"/utf-8\",\n"
|
||||
" \"/DBUILD_DEBUG=1\",\n"
|
||||
" \"/IJuliet\",\n"
|
||||
" \"/FIcore/core_inc.h\",\n"
|
||||
"%s"
|
||||
" \"-c\",\n"
|
||||
" \"%s\"\n"
|
||||
" ]\n"
|
||||
" }",
|
||||
dirs_to_emit[d], full_file_path, module_inc_flag, full_file_path);
|
||||
}
|
||||
}
|
||||
|
||||
file_list_free(&module_files);
|
||||
}
|
||||
} while (FindNextFileA(find_handle, &find_data));
|
||||
|
||||
FindClose(find_handle);
|
||||
}
|
||||
|
||||
// 2. Scan legacy directories so existing files keep working with Neovim LSP
|
||||
const char* legacy_dirs[] = {
|
||||
"Juliet/src",
|
||||
"Game",
|
||||
"JulietApp",
|
||||
"JulietShaderCompiler",
|
||||
"External/imgui"
|
||||
};
|
||||
|
||||
for (size_t l = 0; l < sizeof(legacy_dirs) / sizeof(legacy_dirs[0]); l++)
|
||||
{
|
||||
char search_path[512];
|
||||
strncpy_s(search_path, sizeof(search_path), legacy_dirs[l], _TRUNCATE);
|
||||
normalize_path_slashes_backward(search_path);
|
||||
|
||||
DWORD attrs = GetFileAttributesA(search_path);
|
||||
if (attrs == INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FileList legacy_files = {0};
|
||||
find_files_recursive(search_path, &legacy_files, false);
|
||||
|
||||
for (FileNode* node = legacy_files.first; node != NULL; node = node->next)
|
||||
{
|
||||
const char* dirs_to_emit[2] = { cwd, (real_cwd[0] && _stricmp(cwd, real_cwd) != 0) ? real_cwd : NULL };
|
||||
|
||||
for (int32 d = 0; d < 2; d++)
|
||||
{
|
||||
if (dirs_to_emit[d] == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_first)
|
||||
{
|
||||
offset += snprintf(json_buf + offset, buf_cap - offset, ",\n");
|
||||
}
|
||||
is_first = false;
|
||||
|
||||
char full_file_path[512];
|
||||
snprintf(full_file_path, sizeof(full_file_path), "%s/%s", dirs_to_emit[d], node->path);
|
||||
const char* lang_flag = str_ends_with_no_case(full_file_path, ".c") ? "/clang:-std=c99" : "/std:c++20";
|
||||
|
||||
offset += snprintf(json_buf + offset, buf_cap - offset,
|
||||
" {\n"
|
||||
" \"directory\": \"%s\",\n"
|
||||
" \"file\": \"%s\",\n"
|
||||
" \"arguments\": [\n"
|
||||
" \"clang-cl.exe\",\n"
|
||||
" \"--driver-mode=cl\",\n"
|
||||
" \"/nologo\",\n"
|
||||
" \"%s\",\n"
|
||||
" \"/W4\",\n"
|
||||
" \"/utf-8\",\n"
|
||||
" \"/DJULIET_WIN32\",\n"
|
||||
" \"/DUNICODE\",\n"
|
||||
" \"/D_UNICODE\",\n"
|
||||
" \"/DWIN32_LEAN_AND_MEAN\",\n"
|
||||
" \"/D_CRT_SECURE_NO_WARNINGS\",\n"
|
||||
" \"/DDEBUG\",\n"
|
||||
" \"/DJULIET_DEBUG\",\n"
|
||||
" \"/DPROFILING_ENABLED\",\n"
|
||||
" \"/DJULIET_ENABLE_IMGUI\",\n"
|
||||
" \"/DIMGUI_DEFINE_MATH_OPERATORS\",\n"
|
||||
" \"/DJULIET_EXPORT\",\n"
|
||||
" \"/DIMGUI_API=__declspec(dllexport)\",\n"
|
||||
" \"/IJuliet/include\",\n"
|
||||
" \"/IJuliet/src\",\n"
|
||||
" \"/IJuliet\",\n"
|
||||
" \"/IGame\",\n"
|
||||
" \"/IExternal/imgui\",\n"
|
||||
" \"/IExternal/imgui/backends\",\n"
|
||||
" \"/FICore/PCH.h\",\n"
|
||||
" \"-c\",\n"
|
||||
" \"%s\"\n"
|
||||
" ]\n"
|
||||
" }",
|
||||
dirs_to_emit[d], full_file_path, lang_flag, full_file_path);
|
||||
}
|
||||
}
|
||||
|
||||
file_list_free(&legacy_files);
|
||||
}
|
||||
|
||||
offset += snprintf(json_buf + offset, buf_cap - offset, "\n]\n");
|
||||
|
||||
bool success = write_entire_file("compile_commands.json", json_buf, offset);
|
||||
if (success)
|
||||
{
|
||||
printf("[SUCCESS] Generated compile_commands.json\n");
|
||||
}
|
||||
|
||||
free(json_buf);
|
||||
}
|
||||
|
||||
static void generate_vs_files(void)
|
||||
{
|
||||
CreateDirectoryA("vs", NULL);
|
||||
|
||||
// Discover modules in Juliet/
|
||||
ProjectInfo appbin_project = {0};
|
||||
strncpy_s(appbin_project.name, sizeof(appbin_project.name), "appbin", _TRUNCATE);
|
||||
generate_deterministic_guid(appbin_project.name, appbin_project.guid, sizeof(appbin_project.guid));
|
||||
|
||||
// Gather all new module files for appbin project
|
||||
WIN32_FIND_DATAA find_data;
|
||||
HANDLE find_handle = FindFirstFileA("Juliet\\*", &find_data);
|
||||
if (find_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (strcmp(find_data.cFileName, ".") == 0 || strcmp(find_data.cFileName, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if (_stricmp(find_data.cFileName, "src") == 0 || _stricmp(find_data.cFileName, "include") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char module_dir[512];
|
||||
snprintf(module_dir, sizeof(module_dir), "Juliet\\%s", find_data.cFileName);
|
||||
|
||||
FileList all_files = {0};
|
||||
find_files_recursive(module_dir, &all_files, true);
|
||||
|
||||
for (FileNode* node = all_files.first; node != NULL; node = node->next)
|
||||
{
|
||||
if (is_c_source_file(node->path))
|
||||
{
|
||||
file_list_push(&appbin_project.c_files, node->path);
|
||||
}
|
||||
else if (is_c_header_file(node->path))
|
||||
{
|
||||
file_list_push(&appbin_project.h_files, node->path);
|
||||
}
|
||||
}
|
||||
|
||||
file_list_free(&all_files);
|
||||
}
|
||||
} while (FindNextFileA(find_handle, &find_data));
|
||||
|
||||
FindClose(find_handle);
|
||||
}
|
||||
|
||||
// 1. Generate vs/appbin.vcxproj
|
||||
size_t buf_cap = 2 * 1024 * 1024;
|
||||
char* vcxproj_buf = (char*)malloc(buf_cap);
|
||||
Assert(vcxproj_buf != NULL);
|
||||
|
||||
int32 offset = 0;
|
||||
offset += snprintf(vcxproj_buf + offset, buf_cap - offset,
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
"<Project DefaultTargets=\"Build\" ToolsVersion=\"17.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
|
||||
" <ItemGroup Label=\"ProjectConfigurations\">\n"
|
||||
" <ProjectConfiguration Include=\"Debug|x64\">\n"
|
||||
" <Configuration>Debug</Configuration>\n"
|
||||
" <Platform>x64</Platform>\n"
|
||||
" </ProjectConfiguration>\n"
|
||||
" <ProjectConfiguration Include=\"Release|x64\">\n"
|
||||
" <Configuration>Release</Configuration>\n"
|
||||
" <Platform>x64</Platform>\n"
|
||||
" </ProjectConfiguration>\n"
|
||||
" </ItemGroup>\n"
|
||||
" <PropertyGroup Label=\"Globals\">\n"
|
||||
" <ProjectGuid>{%s}</ProjectGuid>\n"
|
||||
" <Keyword>MakeFileProj</Keyword>\n"
|
||||
" <ProjectName>appbin</ProjectName>\n"
|
||||
" </PropertyGroup>\n"
|
||||
" <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n"
|
||||
" <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n"
|
||||
" <ConfigurationType>Makefile</ConfigurationType>\n"
|
||||
" <UseDebugLibraries>true</UseDebugLibraries>\n"
|
||||
" <PlatformToolset>v143</PlatformToolset>\n"
|
||||
" </PropertyGroup>\n"
|
||||
" <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n"
|
||||
" <ConfigurationType>Makefile</ConfigurationType>\n"
|
||||
" <UseDebugLibraries>false</UseDebugLibraries>\n"
|
||||
" <PlatformToolset>v143</PlatformToolset>\n"
|
||||
" </PropertyGroup>\n"
|
||||
" <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n"
|
||||
" <ImportGroup Label=\"ExtensionSettings\" />\n"
|
||||
" <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n"
|
||||
" <NMakeBuildCommandLine>cd $(SolutionDir)..\\ & new_build.bat appbin debug</NMakeBuildCommandLine>\n"
|
||||
" <NMakeReBuildCommandLine>cd $(SolutionDir)..\\ & new_build.bat clean & new_build.bat appbin debug</NMakeReBuildCommandLine>\n"
|
||||
" <NMakeCleanCommandLine>cd $(SolutionDir)..\\ & new_build.bat clean</NMakeCleanCommandLine>\n"
|
||||
" <NMakeOutput>$(SolutionDir)..\\build\\appbin.exe</NMakeOutput>\n"
|
||||
" <NMakeIncludeSearchPath>$(SolutionDir)..\\Juliet;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>\n"
|
||||
" <NMakePreprocessorDefinitions>BUILD_DEBUG=1;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>\n"
|
||||
" </PropertyGroup>\n"
|
||||
" <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n"
|
||||
" <NMakeBuildCommandLine>cd $(SolutionDir)..\\ & new_build.bat appbin release</NMakeBuildCommandLine>\n"
|
||||
" <NMakeReBuildCommandLine>cd $(SolutionDir)..\\ & new_build.bat clean & new_build.bat appbin release</NMakeReBuildCommandLine>\n"
|
||||
" <NMakeCleanCommandLine>cd $(SolutionDir)..\\ & new_build.bat clean</NMakeCleanCommandLine>\n"
|
||||
" <NMakeOutput>$(SolutionDir)..\\build\\appbin.exe</NMakeOutput>\n"
|
||||
" <NMakeIncludeSearchPath>$(SolutionDir)..\\Juliet;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>\n"
|
||||
" <NMakePreprocessorDefinitions>BUILD_DEBUG=0;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>\n"
|
||||
" </PropertyGroup>\n"
|
||||
" <ItemGroup>\n",
|
||||
appbin_project.guid);
|
||||
|
||||
for (FileNode* node = appbin_project.c_files.first; node != NULL; node = node->next)
|
||||
{
|
||||
char backslash_path[512];
|
||||
strncpy_s(backslash_path, sizeof(backslash_path), node->path, _TRUNCATE);
|
||||
normalize_path_slashes_backward(backslash_path);
|
||||
offset += snprintf(vcxproj_buf + offset, buf_cap - offset,
|
||||
" <ClCompile Include=\"..\\%s\" />\n", backslash_path);
|
||||
}
|
||||
offset += snprintf(vcxproj_buf + offset, buf_cap - offset, " </ItemGroup>\n <ItemGroup>\n");
|
||||
|
||||
for (FileNode* node = appbin_project.h_files.first; node != NULL; node = node->next)
|
||||
{
|
||||
char backslash_path[512];
|
||||
strncpy_s(backslash_path, sizeof(backslash_path), node->path, _TRUNCATE);
|
||||
normalize_path_slashes_backward(backslash_path);
|
||||
offset += snprintf(vcxproj_buf + offset, buf_cap - offset,
|
||||
" <ClInclude Include=\"..\\%s\" />\n", backslash_path);
|
||||
}
|
||||
offset += snprintf(vcxproj_buf + offset, buf_cap - offset, " </ItemGroup>\n");
|
||||
|
||||
if (GetFileAttributesA("Natvis") != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
offset += snprintf(vcxproj_buf + offset, buf_cap - offset,
|
||||
" <ItemGroup>\n"
|
||||
" <Natvis Include=\"..\\Natvis\\Juliet.natvis\" />\n"
|
||||
" <Natvis Include=\"..\\Natvis\\String.natvis\" />\n"
|
||||
" </ItemGroup>\n");
|
||||
}
|
||||
|
||||
offset += snprintf(vcxproj_buf + offset, buf_cap - offset,
|
||||
" <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n"
|
||||
"</Project>\n");
|
||||
|
||||
write_entire_file("vs\\appbin.vcxproj", vcxproj_buf, offset);
|
||||
printf("[SUCCESS] Generated vs\\appbin.vcxproj\n");
|
||||
free(vcxproj_buf);
|
||||
|
||||
// 2. Generate vs/appbin.vcxproj.filters
|
||||
char* filters_buf = (char*)malloc(buf_cap);
|
||||
Assert(filters_buf != NULL);
|
||||
|
||||
int32 f_offset = 0;
|
||||
f_offset += snprintf(filters_buf + f_offset, buf_cap - f_offset,
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
|
||||
"<Project ToolsVersion=\"17.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
|
||||
" <ItemGroup>\n"
|
||||
" <Filter Include=\"core\" />\n"
|
||||
" <Filter Include=\"appbin\" />\n"
|
||||
" </ItemGroup>\n"
|
||||
" <ItemGroup>\n");
|
||||
|
||||
for (FileNode* node = appbin_project.c_files.first; node != NULL; node = node->next)
|
||||
{
|
||||
char backslash_path[512];
|
||||
strncpy_s(backslash_path, sizeof(backslash_path), node->path, _TRUNCATE);
|
||||
normalize_path_slashes_backward(backslash_path);
|
||||
|
||||
const char* filter = strstr(node->path, "core/") ? "core" : "appbin";
|
||||
f_offset += snprintf(filters_buf + f_offset, buf_cap - f_offset,
|
||||
" <ClCompile Include=\"..\\%s\">\n"
|
||||
" <Filter>%s</Filter>\n"
|
||||
" </ClCompile>\n", backslash_path, filter);
|
||||
}
|
||||
f_offset += snprintf(filters_buf + f_offset, buf_cap - f_offset, " </ItemGroup>\n <ItemGroup>\n");
|
||||
|
||||
for (FileNode* node = appbin_project.h_files.first; node != NULL; node = node->next)
|
||||
{
|
||||
char backslash_path[512];
|
||||
strncpy_s(backslash_path, sizeof(backslash_path), node->path, _TRUNCATE);
|
||||
normalize_path_slashes_backward(backslash_path);
|
||||
|
||||
const char* filter = strstr(node->path, "core/") ? "core" : "appbin";
|
||||
f_offset += snprintf(filters_buf + f_offset, buf_cap - f_offset,
|
||||
" <ClInclude Include=\"..\\%s\">\n"
|
||||
" <Filter>%s</Filter>\n"
|
||||
" </ClInclude>\n", backslash_path, filter);
|
||||
}
|
||||
f_offset += snprintf(filters_buf + f_offset, buf_cap - f_offset, " </ItemGroup>\n");
|
||||
|
||||
if (GetFileAttributesA("Natvis") != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
f_offset += snprintf(filters_buf + f_offset, buf_cap - f_offset,
|
||||
" <ItemGroup>\n"
|
||||
" <Filter Include=\"Natvis\" />\n"
|
||||
" </ItemGroup>\n"
|
||||
" <ItemGroup>\n"
|
||||
" <Natvis Include=\"..\\Natvis\\Juliet.natvis\">\n"
|
||||
" <Filter>Natvis</Filter>\n"
|
||||
" </Natvis>\n"
|
||||
" <Natvis Include=\"..\\Natvis\\String.natvis\">\n"
|
||||
" <Filter>Natvis</Filter>\n"
|
||||
" </Natvis>\n"
|
||||
" </ItemGroup>\n");
|
||||
}
|
||||
|
||||
f_offset += snprintf(filters_buf + f_offset, buf_cap - f_offset, "</Project>\n");
|
||||
|
||||
write_entire_file("vs\\appbin.vcxproj.filters", filters_buf, f_offset);
|
||||
printf("[SUCCESS] Generated vs\\appbin.vcxproj.filters\n");
|
||||
free(filters_buf);
|
||||
|
||||
// 3. Generate vs/new_Juliet.sln
|
||||
char sln_buf[4096];
|
||||
int32 s_offset = snprintf(sln_buf, sizeof(sln_buf),
|
||||
"Microsoft Visual Studio Solution File, Format Version 12.00\n"
|
||||
"# Visual Studio Version 17\n"
|
||||
"VisualStudioVersion = 17.0.31903.59\n"
|
||||
"MinimumVisualStudioVersion = 10.0.40219.1\n"
|
||||
"Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"appbin\", \"appbin.vcxproj\", \"{%s}\"\n"
|
||||
"EndProject\n"
|
||||
"Global\n"
|
||||
" GlobalSection(SolutionConfigurationPlatforms) = preSolution\n"
|
||||
" Debug|x64 = Debug|x64\n"
|
||||
" Release|x64 = Release|x64\n"
|
||||
" EndGlobalSection\n"
|
||||
" GlobalSection(ProjectConfigurationPlatforms) = postSolution\n"
|
||||
" {%s}.Debug|x64.ActiveCfg = Debug|x64\n"
|
||||
" {%s}.Debug|x64.Build.0 = Debug|x64\n"
|
||||
" {%s}.Release|x64.ActiveCfg = Release|x64\n"
|
||||
" {%s}.Release|x64.Build.0 = Release|x64\n"
|
||||
" EndGlobalSection\n"
|
||||
" GlobalSection(SolutionProperties) = preSolution\n"
|
||||
" HideSolutionNode = FALSE\n"
|
||||
" EndGlobalSection\n"
|
||||
"EndGlobal\n",
|
||||
appbin_project.guid,
|
||||
appbin_project.guid,
|
||||
appbin_project.guid,
|
||||
appbin_project.guid,
|
||||
appbin_project.guid);
|
||||
|
||||
write_entire_file("vs\\new_Juliet.sln", sln_buf, s_offset);
|
||||
printf("[SUCCESS] Generated vs\\new_Juliet.sln\n");
|
||||
|
||||
file_list_free(&appbin_project.c_files);
|
||||
file_list_free(&appbin_project.h_files);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
bool do_compile_commands = false;
|
||||
bool do_vs = false;
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
do_compile_commands = true;
|
||||
do_vs = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if (_stricmp(argv[i], "all") == 0)
|
||||
{
|
||||
do_compile_commands = true;
|
||||
do_vs = true;
|
||||
}
|
||||
else if (_stricmp(argv[i], "compile_commands") == 0 || _stricmp(argv[i], "json") == 0 || _stricmp(argv[i], "lsp") == 0)
|
||||
{
|
||||
do_compile_commands = true;
|
||||
}
|
||||
else if (_stricmp(argv[i], "vs") == 0 || _stricmp(argv[i], "sln") == 0 || _stricmp(argv[i], "vcxproj") == 0)
|
||||
{
|
||||
do_vs = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[INFO] Unknown argument '%s', generating all by default.\n", argv[i]);
|
||||
do_compile_commands = true;
|
||||
do_vs = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (do_compile_commands)
|
||||
{
|
||||
generate_compile_commands();
|
||||
}
|
||||
|
||||
if (do_vs)
|
||||
{
|
||||
generate_vs_files();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user