Setup proper project skeleton with 2 stage build

This commit is contained in:
Edward R. Gonzalez 2023-09-08 15:14:09 -04:00
parent 60e7d1075a
commit 0376a22775
6 changed files with 234 additions and 180 deletions

View File

@ -2,10 +2,20 @@
Any code I do for this series will be here. Any code I do for this series will be here.
Building requires msvc or llvm's clang + lld, and powershell 7
## Scripts ## Scripts
* `build.ps1` - Builds the project use `.\scripts\build msvc` or `.\scripts\build clang`, add `release` to build in release mode * `build.ps1` - Builds the project use `.\scripts\build msvc` or `.\scripts\build clang`, add `release` to build in release mode
* `clean.ps1` - Cleans the project * `clean.ps1` - Cleans the project
* `update.ps1` - Updates the project dependencies to their latest from their respective repos. (Not done automatically on build) * `update.ps1` - Updates the project dependencies to their latest from their respective repos. (Not done automatically on build)
## Notes
Building requires msvc or llvm's clang + lld, and powershell 7
The build is done in two stages:
1. Build and run metaprogram to scan and generate dependent code.
2. Build the handmade hero runtime.

View File

@ -8657,174 +8657,6 @@ struct Builder
}; };
#pragma endregion Builder #pragma endregion Builder
#pragma region Scanner
// This is a simple file reader that reads the entire file into memory.
// It has an extra option to skip the first few lines for undesired includes.
// This is done so that includes can be kept in dependency and component files so that intellisense works.
Code scan_file( char const* path )
{
FileInfo file;
FileError error = file_open_mode( &file, EFileMode_READ, path );
if ( error != EFileError_NONE )
{
GEN_FATAL( "scan_file: Could not open: %s", path );
}
sw fsize = file_size( &file );
if ( fsize <= 0 )
{
GEN_FATAL( "scan_file: %s is empty", path );
}
String str = String::make_reserve( GlobalAllocator, fsize );
file_read( &file, str, fsize );
str.get_header().Length = fsize;
// Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks
// Its designed so that the directive should be the first thing in the file.
// Anything that comes before it will also be omitted.
{
#define current ( *scanner )
#define matched 0
#define move_fwd() \
do \
{ \
++scanner; \
--left; \
} while ( 0 )
const StrC directive_start = txt( "ifdef" );
const StrC directive_end = txt( "endif" );
const StrC def_intellisense = txt( "GEN_INTELLISENSE_DIRECTIVES" );
bool found_directive = false;
char const* scanner = str.Data;
s32 left = fsize;
while ( left )
{
// Processing directive.
if ( current == '#' )
{
move_fwd();
while ( left && char_is_space( current ) )
move_fwd();
if ( ! found_directive )
{
if ( left && str_compare( scanner, directive_start.Ptr, directive_start.Len ) == matched )
{
scanner += directive_start.Len;
left -= directive_start.Len;
while ( left && char_is_space( current ) )
move_fwd();
if ( left && str_compare( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched )
{
scanner += def_intellisense.Len;
left -= def_intellisense.Len;
found_directive = true;
}
}
// Skip to end of line
while ( left && current != '\r' && current != '\n' )
move_fwd();
move_fwd();
if ( left && current == '\n' )
move_fwd();
continue;
}
if ( left && str_compare( scanner, directive_end.Ptr, directive_end.Len ) == matched )
{
scanner += directive_end.Len;
left -= directive_end.Len;
// Skip to end of line
while ( left && current != '\r' && current != '\n' )
move_fwd();
move_fwd();
if ( left && current == '\n' )
move_fwd();
// sptr skip_size = fsize - left;
if ( ( scanner + 2 ) >= ( str.Data + fsize ) )
{
mem_move( str, scanner, left );
str.get_header().Length = left;
break;
}
mem_move( str, scanner, left );
str.get_header().Length = left;
break;
}
}
move_fwd();
}
#undef move_fwd
#undef matched
#undef current
}
file_close( &file );
return untyped_str( str );
}
#if 0
struct Policy
{
// Nothing for now.
};
struct SymbolInfo
{
StringCached File;
char const* Marker;
Code Signature;
};
struct Scanner
{
struct RequestEntry
{
SymbolInfo Info;
};
struct Receipt
{
StringCached File;
Code Defintion;
bool Result;
};
AllocatorInfo MemAlloc;
static void set_allocator( AllocatorInfo allocator );
Array<FileInfo> Files;
String Buffer;
Array<RequestEntry> Requests;
void add_files( s32 num, char const** files );
void add( SymbolInfo signature, Policy policy );
bool process_requests( Array<Receipt> out_receipts );
};
#endif
#pragma endregion Scanner
GEN_NS_END GEN_NS_END
#pragma region GENCPP IMPLEMENTATION GUARD #pragma region GENCPP IMPLEMENTATION GUARD
@ -23089,6 +22921,174 @@ void Builder::write()
#pragma endregion Builder #pragma endregion Builder
#pragma region Scanner
// This is a simple file reader that reads the entire file into memory.
// It has an extra option to skip the first few lines for undesired includes.
// This is done so that includes can be kept in dependency and component files so that intellisense works.
Code scan_file( char const* path )
{
FileInfo file;
FileError error = file_open_mode( &file, EFileMode_READ, path );
if ( error != EFileError_NONE )
{
GEN_FATAL( "scan_file: Could not open: %s", path );
}
sw fsize = file_size( &file );
if ( fsize <= 0 )
{
GEN_FATAL( "scan_file: %s is empty", path );
}
String str = String::make_reserve( GlobalAllocator, fsize );
file_read( &file, str, fsize );
str.get_header().Length = fsize;
// Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks
// Its designed so that the directive should be the first thing in the file.
// Anything that comes before it will also be omitted.
{
#define current ( *scanner )
#define matched 0
#define move_fwd() \
do \
{ \
++scanner; \
--left; \
} while ( 0 )
const StrC directive_start = txt( "ifdef" );
const StrC directive_end = txt( "endif" );
const StrC def_intellisense = txt( "GEN_INTELLISENSE_DIRECTIVES" );
bool found_directive = false;
char const* scanner = str.Data;
s32 left = fsize;
while ( left )
{
// Processing directive.
if ( current == '#' )
{
move_fwd();
while ( left && char_is_space( current ) )
move_fwd();
if ( ! found_directive )
{
if ( left && str_compare( scanner, directive_start.Ptr, directive_start.Len ) == matched )
{
scanner += directive_start.Len;
left -= directive_start.Len;
while ( left && char_is_space( current ) )
move_fwd();
if ( left && str_compare( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched )
{
scanner += def_intellisense.Len;
left -= def_intellisense.Len;
found_directive = true;
}
}
// Skip to end of line
while ( left && current != '\r' && current != '\n' )
move_fwd();
move_fwd();
if ( left && current == '\n' )
move_fwd();
continue;
}
if ( left && str_compare( scanner, directive_end.Ptr, directive_end.Len ) == matched )
{
scanner += directive_end.Len;
left -= directive_end.Len;
// Skip to end of line
while ( left && current != '\r' && current != '\n' )
move_fwd();
move_fwd();
if ( left && current == '\n' )
move_fwd();
// sptr skip_size = fsize - left;
if ( ( scanner + 2 ) >= ( str.Data + fsize ) )
{
mem_move( str, scanner, left );
str.get_header().Length = left;
break;
}
mem_move( str, scanner, left );
str.get_header().Length = left;
break;
}
}
move_fwd();
}
#undef move_fwd
#undef matched
#undef current
}
file_close( &file );
return untyped_str( str );
}
#if 0
struct Policy
{
// Nothing for now.
};
struct SymbolInfo
{
StringCached File;
char const* Marker;
Code Signature;
};
struct Scanner
{
struct RequestEntry
{
SymbolInfo Info;
};
struct Receipt
{
StringCached File;
Code Defintion;
bool Result;
};
AllocatorInfo MemAlloc;
static void set_allocator( AllocatorInfo allocator );
Array<FileInfo> Files;
String Buffer;
Array<RequestEntry> Requests;
void add_files( s32 num, char const** files );
void add( SymbolInfo signature, Policy policy );
bool process_requests( Array<Receipt> out_receipts );
};
#endif
#pragma endregion Scanner
GEN_NS_END GEN_NS_END
#endif #endif

View File

@ -0,0 +1,17 @@
#if GEN_TIME
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_IMPLEMENTATION
#define GEN_BENCHMARK
#define GEN_ENFORCE_STRONG_CODE_TYPES
#include "gen.hpp"
using namespace gen;
int gen_main()
{
gen::init();
log_fmt("Generating code for Handmade Hero\n");
gen::deinit();
return 0;
}
#endif

View File

@ -0,0 +1,8 @@
#include <stdio.h>
int main()
{
puts("Handmade Hero!");
return 0;
}

View File

@ -1,7 +0,0 @@
#include "stdio.h"
int main()
{
puts( "Hello World!\n" );
return 0;
}

View File

@ -288,6 +288,7 @@ if ( $vendor -match "msvc" )
$path_project = Join-Path $path_root 'project' $path_project = Join-Path $path_root 'project'
$path_build = Join-Path $path_project 'build' $path_build = Join-Path $path_project 'build'
$path_deps = Join-Path $path_project 'dependencies' $path_deps = Join-Path $path_project 'dependencies'
$path_gen = Join-Path $path_project 'gen'
$update_deps = Join-Path $PSScriptRoot 'update_deps.ps1' $update_deps = Join-Path $PSScriptRoot 'update_deps.ps1'
@ -300,14 +301,39 @@ if ( (Test-Path $path_deps) -eq $false ) {
} }
$includes = @( $includes = @(
$path_gen,
$path_project, $path_project,
$path_deps $path_deps
) )
$unit = Join-Path $path_project 'sanity.cpp' $compiler_args = @(
$executable = Join-Path $path_build 'sanity.exe' ($flag_define + 'GEN_TIME')
)
#region Handmade Generate
$unit = Join-Path $path_gen 'gen_handmade.cpp'
$executable = Join-Path $path_build 'gen_handmade.exe'
build-simple $includes $compiler_args $unit $executable
write-host "Compiled Handmade Generate`n"
& $executable
if ( $false ) {
Remove-Item (Get-ChildItem -Path $path_build -Recurse -Force)
}
#endregion Handmade Generate
#region Handmade Runtime
$unit = Join-Path $path_project 'handmade_win32.cpp'
$executable = Join-Path $path_build 'handmade_win32.exe'
$compile_args = @( $compile_args = @(
) )
build-simple $includes $compiler_args $unit $executable build-simple $includes $compiler_args $unit $executable
write-host "Compiled Handmade Runtime`n"
#endregion Handmade Runtime
Pop-Location