mirror of
				https://github.com/Ed94/HandmadeHero.git
				synced 2025-10-31 06:50:54 -07:00 
			
		
		
		
	Setup proper project skeleton with 2 stage build
This commit is contained in:
		
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							| @@ -2,10 +2,20 @@ | ||||
|  | ||||
| Any code I do for this series will be here. | ||||
|  | ||||
| Building requires msvc or llvm's clang + lld, and powershell 7 | ||||
|  | ||||
|  | ||||
| ## Scripts | ||||
|  | ||||
| * `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 | ||||
| * `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. | ||||
|  | ||||
|   | ||||
| @@ -8657,174 +8657,6 @@ struct 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 | ||||
|  | ||||
| #pragma region GENCPP IMPLEMENTATION GUARD | ||||
| @@ -23089,6 +22921,174 @@ void Builder::write() | ||||
|  | ||||
| #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 | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										17
									
								
								project/gen/gen_handmade.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								project/gen/gen_handmade.cpp
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										8
									
								
								project/handmade_win32.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								project/handmade_win32.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #include <stdio.h> | ||||
|  | ||||
| int main() | ||||
| { | ||||
| 	puts("Handmade Hero!"); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,7 +0,0 @@ | ||||
| #include "stdio.h" | ||||
|  | ||||
| int main() | ||||
| { | ||||
| 	puts( "Hello World!\n" ); | ||||
| 	return 0; | ||||
| } | ||||
| @@ -285,9 +285,10 @@ if ( $vendor -match "msvc" ) | ||||
| } | ||||
| #endregion Configuration | ||||
|  | ||||
| $path_project = Join-Path $path_root 'project' | ||||
| $path_project = Join-Path $path_root    'project' | ||||
| $path_build   = Join-Path $path_project 'build' | ||||
| $path_deps    = Join-Path $path_project 'dependencies' | ||||
| $path_gen     = Join-Path $path_project 'gen' | ||||
|  | ||||
| $update_deps = Join-Path $PSScriptRoot 'update_deps.ps1' | ||||
|  | ||||
| @@ -300,14 +301,39 @@ if ( (Test-Path $path_deps) -eq $false ) { | ||||
| } | ||||
|  | ||||
| $includes = @( | ||||
| 	$path_gen, | ||||
| 	$path_project, | ||||
| 	$path_deps | ||||
| ) | ||||
|  | ||||
| $unit       = Join-Path $path_project 'sanity.cpp' | ||||
| $executable = Join-Path $path_build   'sanity.exe' | ||||
| $compiler_args = @( | ||||
| 	($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 = @( | ||||
| ) | ||||
|  | ||||
| build-simple $includes $compiler_args $unit $executable | ||||
| write-host "Compiled Handmade Runtime`n" | ||||
| #endregion Handmade Runtime | ||||
|  | ||||
| Pop-Location | ||||
|   | ||||
		Reference in New Issue
	
	Block a user